import 'package:flutter/foundation.dart';
import 'control_plane_status_client.dart';

class ControlPlaneStatusController extends ChangeNotifier {
  final ControlPlaneStatusRepository statusRepository;

  List<FleetEdgeView> _edges = [];
  bool _loadingEdges = false;
  String? _edgesError;
  String? _selectedEdgeId;

  final Map<String, EdgeStatusResponseView> _edgeStatuses = {};
  final Map<String, bool> _loadingStatuses = {};
  final Map<String, String?> _statusErrors = {};

  final Map<String, List<EdgeNodeEventView>> _edgeEvents = {};
  final Map<String, bool> _loadingEvents = {};
  final Map<String, String?> _eventErrors = {};

  bool _disposed = false;

  ControlPlaneStatusController({required this.statusRepository});

  // Getters
  List<FleetEdgeView> get edges => _edges;
  bool get loadingEdges => _loadingEdges;
  String? get edgesError => _edgesError;
  String? get selectedEdgeId => _selectedEdgeId;

  Map<String, EdgeStatusResponseView> get edgeStatuses => _edgeStatuses;
  Map<String, bool> get loadingStatuses => _loadingStatuses;
  Map<String, String?> get statusErrors => _statusErrors;

  Map<String, List<EdgeNodeEventView>> get edgeEvents => _edgeEvents;
  Map<String, bool> get loadingEvents => _loadingEvents;
  Map<String, String?> get eventErrors => _eventErrors;

  @override
  void dispose() {
    _disposed = true;
    super.dispose();
  }

  void _notifyIfActive() {
    if (!_disposed) {
      notifyListeners();
    }
  }

  void selectEdge(String edgeId) {
    if (_disposed) return;
    if (_selectedEdgeId == edgeId) return;
    _selectedEdgeId = edgeId;
    _notifyIfActive();
    fetchEdgeDetails(edgeId);
  }

  Future<void> fetchEdges() async {
    if (_disposed) return;
    _loadingEdges = true;
    _edgesError = null;
    _notifyIfActive();

    try {
      final fleetResponse = await statusRepository.fetchFleetStatus();
      if (_disposed) return;
      _edges = fleetResponse.edges;
      _loadingEdges = false;

      // Normalize selection: check if the previously selected edge is still present
      final hasSelected = _edges.any((e) => e.edgeId == _selectedEdgeId);
      if (!hasSelected) {
        // Clear stale status/events/loading/error cache to prevent leak/inconsistency
        if (_selectedEdgeId != null) {
          _edgeStatuses.remove(_selectedEdgeId);
          _loadingStatuses.remove(_selectedEdgeId);
          _statusErrors.remove(_selectedEdgeId);
          _edgeEvents.remove(_selectedEdgeId);
          _loadingEvents.remove(_selectedEdgeId);
          _eventErrors.remove(_selectedEdgeId);
        }

        if (_edges.isNotEmpty) {
          _selectedEdgeId = _edges.first.edgeId;
        } else {
          _selectedEdgeId = null;
        }
      }
      _notifyIfActive();

      if (_selectedEdgeId != null) {
        await fetchEdgeDetails(_selectedEdgeId!);
      }
    } catch (e) {
      if (_disposed) return;
      _edgesError = e.toString();
      _loadingEdges = false;
      _notifyIfActive();
    }
  }

  Future<void> fetchEdgeDetails(String edgeId) async {
    if (_disposed) return;
    await Future.wait([fetchEdgeStatus(edgeId), fetchEdgeEvents(edgeId)]);
    if (_disposed) return;
  }

  Future<void> fetchEdgeStatus(String edgeId) async {
    if (_disposed) return;
    _loadingStatuses[edgeId] = true;
    _statusErrors[edgeId] = null;
    _notifyIfActive();

    try {
      final status = await statusRepository.fetchEdgeStatus(edgeId);
      if (_disposed) return;
      _edgeStatuses[edgeId] = status;
      _loadingStatuses[edgeId] = false;
      _notifyIfActive();
    } catch (e) {
      if (_disposed) return;
      _statusErrors[edgeId] = e.toString();
      _loadingStatuses[edgeId] = false;
      _notifyIfActive();
    }
  }

  Future<void> fetchEdgeEvents(String edgeId) async {
    if (_disposed) return;
    _loadingEvents[edgeId] = true;
    _eventErrors[edgeId] = null;
    _notifyIfActive();

    try {
      final events = await statusRepository.fetchEdgeEvents(edgeId);
      if (_disposed) return;
      _edgeEvents[edgeId] = events;
      _loadingEvents[edgeId] = false;
      _notifyIfActive();
    } catch (e) {
      if (_disposed) return;
      _eventErrors[edgeId] = e.toString();
      _loadingEvents[edgeId] = false;
      _notifyIfActive();
    }
  }

  Future<void> refreshSelectedStatus() async {
    if (_disposed) return;
    if (_selectedEdgeId != null) {
      await fetchEdgeStatus(_selectedEdgeId!);
    }
  }

  Future<void> refreshSelectedEvents() async {
    if (_disposed) return;
    if (_selectedEdgeId != null) {
      await fetchEdgeEvents(_selectedEdgeId!);
    }
  }
}
