import 'dart:convert';
import 'package:http/http.dart' as http;
import 'control_plane_status_dto.dart';

abstract class ControlPlaneStatusRepository {
  Future<List<EdgeRegistryView>> fetchEdges();
  Future<EdgeStatusResponseView> fetchEdgeStatus(String edgeId);
  Future<List<EdgeNodeEventView>> fetchEdgeEvents(String edgeId);
  Future<FleetStatusResponseView> fetchFleetStatus();
  Future<EdgeOperationsResponseView> fetchEdgeOperations(String edgeId);
  Future<EdgeCommandResponseView> sendEdgeCommand(
    String edgeId,
    String operation, {
    String? targetSelector,
    Map<String, String>? parameters,
  });
}

class HttpControlPlaneStatusRepository implements ControlPlaneStatusRepository {
  final String baseUrl;
  final http.Client _client;
  final bool _ownsClient;

  HttpControlPlaneStatusRepository({required this.baseUrl, http.Client? client})
    : _client = client ?? http.Client(),
      _ownsClient = client == null;

  http.Client get _httpClient => _client;

  void close() {
    if (_ownsClient) {
      _client.close();
    }
  }

  @override
  Future<List<EdgeRegistryView>> fetchEdges() async {
    final response = await _httpClient.get(Uri.parse('$baseUrl/edges'));
    if (response.statusCode != 200) {
      throw Exception('Failed to fetch edges: ${response.statusCode}');
    }
    final body = json.decode(response.body) as Map<String, dynamic>;
    final list = body['edges'] as List? ?? [];
    return list
        .map((e) => EdgeRegistryView.fromJson(e as Map<String, dynamic>))
        .toList();
  }

  @override
  Future<EdgeStatusResponseView> fetchEdgeStatus(String edgeId) async {
    final response = await _httpClient.get(
      Uri.parse('$baseUrl/edges/$edgeId/status'),
    );
    if (response.statusCode != 200) {
      throw Exception(
        'Failed to fetch status for $edgeId: ${response.statusCode}',
      );
    }
    final body = json.decode(response.body) as Map<String, dynamic>;
    return EdgeStatusResponseView.fromJson(body);
  }

  @override
  Future<List<EdgeNodeEventView>> fetchEdgeEvents(String edgeId) async {
    final response = await _httpClient.get(
      Uri.parse('$baseUrl/edges/$edgeId/events'),
    );
    if (response.statusCode != 200) {
      throw Exception(
        'Failed to fetch events for $edgeId: ${response.statusCode}',
      );
    }
    final body = json.decode(response.body) as Map<String, dynamic>;
    final list = body['events'] as List? ?? [];
    return list
        .map((e) => EdgeNodeEventView.fromJson(e as Map<String, dynamic>))
        .toList();
  }

  @override
  Future<FleetStatusResponseView> fetchFleetStatus() async {
    final response = await _httpClient.get(Uri.parse('$baseUrl/fleet/status'));
    if (response.statusCode != 200) {
      throw Exception('Failed to fetch fleet status: ${response.statusCode}');
    }
    final body = json.decode(response.body) as Map<String, dynamic>;
    return FleetStatusResponseView.fromJson(body);
  }

  @override
  Future<EdgeOperationsResponseView> fetchEdgeOperations(String edgeId) async {
    final response = await _httpClient.get(
      Uri.parse('$baseUrl/edges/$edgeId/operations'),
    );
    if (response.statusCode != 200) {
      throw Exception(
        'Failed to fetch operations for $edgeId: ${response.statusCode}',
      );
    }
    final body = json.decode(response.body) as Map<String, dynamic>;
    return EdgeOperationsResponseView.fromJson(body);
  }

  @override
  Future<EdgeCommandResponseView> sendEdgeCommand(
    String edgeId,
    String operation, {
    String? targetSelector,
    Map<String, String>? parameters,
  }) async {
    final Map<String, dynamic> requestBody = {'operation': operation};
    if (targetSelector != null) {
      requestBody['target_selector'] = targetSelector;
    }
    if (parameters != null) {
      requestBody['parameters'] = parameters;
    }

    final response = await _httpClient.post(
      Uri.parse('$baseUrl/edges/$edgeId/commands'),
      headers: {'Content-Type': 'application/json'},
      body: json.encode(requestBody),
    );
    if (response.statusCode != 200 && response.statusCode != 202) {
      throw Exception(
        'Failed to send command to $edgeId: ${response.statusCode}',
      );
    }
    final body = json.decode(response.body) as Map<String, dynamic>;
    return EdgeCommandResponseView.fromJson(body);
  }
}
