import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:xp_models/xp_models.dart';
import 'api_service.dart';

class DashboardProvider extends ChangeNotifier {
  final ApiService _apiService;

  // State variables
  DashboardStats? _stats;
  List<StatsHistory> _statsHistory = [];
  List<Achievement> _achievements = [];
  List<Activity> _activities = [];
  List<FocusSession> _focusSessions = [];
  Map<String, int> _xpBreakdown = {};
  SystemLogResponse? _logs;
  Map<String, dynamic> _config = {};
  List<ApplicationClassification> _classifications = [];
  List<UnclassifiedApplication> _unclassified = [];

  // Loading states
  bool _isLoading = false;
  bool _isStatsLoading = false;
  bool _isHistoryLoading = false;
  bool _isAchievementsLoading = false;
  bool _isActivitiesLoading = false;
  bool _isFocusSessionsLoading = false;
  bool _isXpBreakdownLoading = false;
  bool _isLogsLoading = false;
  bool _isConfigLoading = false;
  bool _isClassificationsLoading = false;
  bool _isUnclassifiedLoading = false;

  // Error states
  String? _error;
  String? _statsError;
  String? _historyError;
  String? _achievementsError;
  String? _activitiesError;
  String? _focusSessionsError;
  String? _xpBreakdownError;
  String? _logsError;
  String? _configError;
  String? _classificationsError;
  String? _unclassifiedError;

  // WebSocket
  StreamSubscription<WebSocketMessage>? _wsSubscription;
  bool _isWebSocketConnected = false;

  // Disposal tracking
  bool _disposed = false;

  DashboardProvider(this._apiService);

  // Getters
  DashboardStats? get stats => _stats;
  List<StatsHistory> get statsHistory => _statsHistory;
  List<Achievement> get achievements => _achievements;
  List<Activity> get activities => _activities;
  List<FocusSession> get focusSessions => _focusSessions;
  Map<String, int> get xpBreakdown => _xpBreakdown;
  SystemLogResponse? get logs => _logs;
  Map<String, dynamic> get config => _config;
  List<ApplicationClassification> get classifications => _classifications;
  List<UnclassifiedApplication> get unclassified => _unclassified;

  // Loading state getters
  bool get isLoading => _isLoading;
  bool get isStatsLoading => _isStatsLoading;
  bool get isHistoryLoading => _isHistoryLoading;
  bool get isAchievementsLoading => _isAchievementsLoading;
  bool get isActivitiesLoading => _isActivitiesLoading;
  bool get isFocusSessionsLoading => _isFocusSessionsLoading;
  bool get isXpBreakdownLoading => _isXpBreakdownLoading;
  bool get isLogsLoading => _isLogsLoading;
  bool get isConfigLoading => _isConfigLoading;
  bool get isClassificationsLoading => _isClassificationsLoading;
  bool get isUnclassifiedLoading => _isUnclassifiedLoading;

  // Error getters
  String? get error => _error;
  String? get statsError => _statsError;
  String? get historyError => _historyError;
  String? get achievementsError => _achievementsError;
  String? get activitiesError => _activitiesError;
  String? get focusSessionsError => _focusSessionsError;
  String? get xpBreakdownError => _xpBreakdownError;
  String? get logsError => _logsError;
  String? get configError => _configError;
  String? get classificationsError => _classificationsError;
  String? get unclassifiedError => _unclassifiedError;

  bool get isWebSocketConnected => _isWebSocketConnected;

  // Initialize dashboard data
  Future<void> initialize() async {
    _isLoading = true;
    _error = null;
    notifyListeners();

    try {
      await Future.wait([
        loadStats(),
        loadStatsHistory(),
        loadAchievements(),
        loadActivities(),
        loadFocusSessions(),
        loadXPBreakdown(),
        loadConfig(),
        loadClassifications(),
        loadUnclassified(),
      ]);

      // Connect WebSocket after initial data load
      await connectWebSocket();
    } catch (e) {
      _error = e.toString();
    } finally {
      _isLoading = false;
      notifyListeners();
    }
  }

  // Load individual data sections
  Future<void> loadStats() async {
    _isStatsLoading = true;
    _statsError = null;
    notifyListeners();

    try {
      _stats = await _apiService.getStats();
    } catch (e) {
      _statsError = e.toString();
    } finally {
      _isStatsLoading = false;
      notifyListeners();
    }
  }

  Future<void> loadStatsHistory({int days = 7}) async {
    _isHistoryLoading = true;
    _historyError = null;
    notifyListeners();

    try {
      _statsHistory = await _apiService.getStatsHistory(days: days);
    } catch (e) {
      _historyError = e.toString();
    } finally {
      _isHistoryLoading = false;
      notifyListeners();
    }
  }

  Future<void> loadAchievements({int limit = 5}) async {
    _isAchievementsLoading = true;
    _achievementsError = null;
    notifyListeners();

    try {
      _achievements = await _apiService.getAchievements(limit: limit);
    } catch (e) {
      _achievementsError = e.toString();
    } finally {
      _isAchievementsLoading = false;
      notifyListeners();
    }
  }

  Future<void> loadActivities({int limit = 100}) async {
    _isActivitiesLoading = true;
    _activitiesError = null;
    notifyListeners();

    try {
      _activities = await _apiService.getActivities(limit: limit);
    } catch (e) {
      _activitiesError = e.toString();
    } finally {
      _isActivitiesLoading = false;
      notifyListeners();
    }
  }

  Future<void> loadFocusSessions({int limit = 50}) async {
    _isFocusSessionsLoading = true;
    _focusSessionsError = null;
    notifyListeners();

    try {
      _focusSessions = await _apiService.getFocusSessions(limit: limit);
    } catch (e) {
      _focusSessionsError = e.toString();
    } finally {
      _isFocusSessionsLoading = false;
      notifyListeners();
    }
  }

  Future<void> loadXPBreakdown({String? date}) async {
    _isXpBreakdownLoading = true;
    _xpBreakdownError = null;
    notifyListeners();

    try {
      _xpBreakdown = await _apiService.getXPBreakdown(date: date);
    } catch (e) {
      _xpBreakdownError = e.toString();
    } finally {
      _isXpBreakdownLoading = false;
      notifyListeners();
    }
  }

  Future<void> loadLogs({int count = 100, LogLevel? level}) async {
    _isLogsLoading = true;
    _logsError = null;
    notifyListeners();

    try {
      _logs = await _apiService.getLogs(count: count, level: level);
    } catch (e) {
      _logsError = e.toString();
    } finally {
      _isLogsLoading = false;
      notifyListeners();
    }
  }

  Future<void> loadConfig() async {
    _isConfigLoading = true;
    _configError = null;
    notifyListeners();

    try {
      _config = await _apiService.getConfig();
    } catch (e) {
      _configError = e.toString();
    } finally {
      _isConfigLoading = false;
      notifyListeners();
    }
  }

  Future<void> updateConfig(Map<String, dynamic> updates) async {
    try {
      await _apiService.updateConfig(updates);
      await loadConfig(); // Reload config after update
    } catch (e) {
      _configError = e.toString();
      notifyListeners();
      rethrow;
    }
  }

  Future<void> loadClassifications() async {
    _isClassificationsLoading = true;
    _classificationsError = null;
    notifyListeners();

    try {
      _classifications = await _apiService.getClassifications();
    } catch (e) {
      _classificationsError = e.toString();
    } finally {
      _isClassificationsLoading = false;
      notifyListeners();
    }
  }

  Future<void> loadUnclassified() async {
    _isUnclassifiedLoading = true;
    _unclassifiedError = null;
    notifyListeners();

    try {
      _unclassified = await _apiService.getUnclassified();
    } catch (e) {
      _unclassifiedError = e.toString();
    } finally {
      _isUnclassifiedLoading = false;
      notifyListeners();
    }
  }

  Future<void> saveClassification(String applicationName, String categoryId) async {
    try {
      final request = ClassificationRequest(applicationName: applicationName, categoryId: categoryId);
      await _apiService.saveClassification(request);

      // Reload classifications and unclassified after saving
      await Future.wait([loadClassifications(), loadUnclassified()]);
    } catch (e) {
      _classificationsError = e.toString();
      notifyListeners();
      rethrow;
    }
  }

  Future<void> deleteClassification(String applicationName) async {
    try {
      await _apiService.deleteClassification(applicationName);

      // Reload classifications and unclassified after deletion
      await Future.wait([loadClassifications(), loadUnclassified()]);
    } catch (e) {
      _classificationsError = e.toString();
      notifyListeners();
      rethrow;
    }
  }

  // WebSocket methods
  Future<void> connectWebSocket() async {
    try {
      await _apiService.connectWebSocket();
      _wsSubscription = _apiService.webSocketStream.listen(
        _handleWebSocketMessage,
        onError: _handleWebSocketError,
        onDone: _handleWebSocketDone,
      );
      _isWebSocketConnected = true;
      notifyListeners();
    } catch (e) {
      debugPrint('Failed to connect WebSocket: $e');
    }
  }

  Future<void> disconnectWebSocket() async {
    await _wsSubscription?.cancel();
    _wsSubscription = null;
    await _apiService.disconnectWebSocket();
    _isWebSocketConnected = false;
    notifyListeners();
  }

  void _handleWebSocketMessage(WebSocketMessage message) {
    switch (message.type) {
      case WebSocketMessageType.statsUpdate:
        if (message.data != null) {
          _stats = DashboardStats.fromJson(message.data!);
          notifyListeners();
        }
        break;
      case WebSocketMessageType.xpBreakdownUpdate:
        if (message.data != null) {
          _xpBreakdown = message.data!.map((key, value) => MapEntry(key, value as int));
          notifyListeners();
        }
        break;
      case WebSocketMessageType.achievementUnlocked:
        // Reload achievements when a new one is unlocked
        loadAchievements();
        break;
      case WebSocketMessageType.levelUp:
        // Reload stats when level changes
        loadStats();
        break;
      case WebSocketMessageType.focusSessionComplete:
        // Reload focus sessions and stats
        Future.wait([loadFocusSessions(), loadStats()]);
        break;
      case WebSocketMessageType.ping:
        // Respond to ping with pong
        _apiService.sendWebSocketMessage(WebSocketMessage.pong());
        break;
      case WebSocketMessageType.pong:
        // Handle pong response (optional)
        break;
    }
  }

  void _handleWebSocketError(error) {
    debugPrint('WebSocket error: $error');
    _isWebSocketConnected = false;

    // Only notify listeners if not disposed
    if (!_disposed) {
      notifyListeners();

      // Try to reconnect after a delay
      Timer(const Duration(seconds: 5), () {
        if (!_disposed && !_isWebSocketConnected) {
          connectWebSocket();
        }
      });
    }
  }

  void _handleWebSocketDone() {
    debugPrint('WebSocket connection closed');
    _isWebSocketConnected = false;

    // Only notify listeners if not disposed
    if (!_disposed) {
      notifyListeners();

      // Try to reconnect after a delay
      Timer(const Duration(seconds: 5), () {
        if (!_disposed && !_isWebSocketConnected) {
          connectWebSocket();
        }
      });
    }
  }

  // Refresh all data
  Future<void> refresh() async {
    await initialize();
  }

  @override
  Future<void> dispose() async {
    _disposed = true;
    await _apiService.dispose();
    super.dispose();
  }
}
