import 'dart:async';
import 'dart:convert';
import 'dart:io';
import '../logging/logger.dart';

class ConfigManager {
  static ConfigManager? _instance;
  static ConfigManager get instance => _instance ??= ConfigManager._();

  ConfigManager._();

  /// Reset the singleton instance (useful for testing)
  static void resetInstance() {
    _instance = null;
  }

  Map<String, dynamic>? _config;
  File? _configFile;
  DateTime? _lastModified;
  bool _isInitialized = false;

  Future<void> initialize([String configPath = 'config/xp_config.json']) async {
    _configFile = File(configPath);
    await _loadConfig();
    _isInitialized = true;

    // Start watching for config changes
    _watchConfigFile();

    Logger.info('Configuration manager initialized with ${_config!.keys.length} sections');
  }

  void _ensureInitialized() {
    if (!_isInitialized || _config == null) {
      _config = _getDefaultConfig();
      _isInitialized = true;
    }
  }

  Future<void> _loadConfig() async {
    try {
      if (_configFile != null && !await _configFile!.exists()) {
        await _createDefaultConfig();
      }

      if (_configFile != null) {
        final content = await _configFile!.readAsString();
        _config = jsonDecode(content);
        _lastModified = await _configFile!.lastModified();
      }

      Logger.info('Configuration loaded successfully');
    } catch (e) {
      Logger.error('Failed to load configuration: $e');
      _config = _getDefaultConfig();
    }
  }

  Future<void> _createDefaultConfig() async {
    if (_configFile != null) {
      await _configFile!.parent.create(recursive: true);
      final defaultConfig = _getDefaultConfig();
      await _configFile!.writeAsString(jsonEncode(defaultConfig));
      Logger.info('Created default configuration file at ${_configFile!.path}');
    }
  }

  Map<String, dynamic> _getDefaultConfig() {
    return {
      "xp_rewards": {
        "base_multipliers": {
          "coding": 10,
          "focused_browsing": 6,
          "collaboration": 7,
          "meetings": 3,
          "misc": 2,
          "uncategorized": 1,
        },
        "time_multipliers": {
          "deep_work_hours": {
            "times": ["09:00-11:00", "14:00-16:00"],
            "multiplier": 1.5,
          },
          "late_night_penalty": {
            "times": ["22:00-06:00"],
            "multiplier": 0.8,
          },
        },
        "focus_session_bonuses": {
          "base_xp_per_minute": 5,
          "milestones": {"60": 100, "120": 200, "180": 500},
        },
        "zoom_multipliers": {"active_meeting": 8, "background_meeting": 5, "zoom_focused": 2, "zoom_background": 0},
      },
      "overlay": {
        "enabled": true,
        "app_path": "",  // Auto-detect if empty
        "duration_seconds": 3,
        "colors": {
          "regular": "#4CAF50",  // Green
          "high": "#FF9800",     // Orange
          "bonus": "#FFC107",    // Amber
        },
      },
      "achievements": {
        "level_based": {
          "5": {
            "name": "Rising Star",
            "description": "Reached level 5 - Your journey begins to shine!",
            "xp_reward": 100,
          },
          "10": {
            "name": "Productivity Warrior",
            "description": "Reached level 10 - You've unlocked desktop blur effects!",
            "xp_reward": 250,
          },
          "15": {
            "name": "Focus Master",
            "description": "Reached level 15 - Your desktop now glows with productivity!",
            "xp_reward": 500,
          },
          "25": {
            "name": "Legendary Achiever",
            "description": "Reached level 25 - You have transcended ordinary productivity!",
            "xp_reward": 1000,
          },
        },
        "focus_based": {
          "deep_focus": {
            "name": "Deep Focus",
            "description": "Maintained a straight hour of focus time in a day",
            "xp_reward": 200,
            "threshold_hours": 1,
          },
          "focus_titan": {
            "name": "Focus Titan",
            "description": "Achieved 4 hours of pure focus - Incredible!",
            "xp_reward": 500,
            "threshold_hours": 4,
          },
        },
        "session_based": {
          "session_master": {
            "name": "Session Master",
            "description": "Completed 5+ focus sessions in one day",
            "xp_reward": 150,
            "threshold_sessions": 5,
          },
        },
        "meeting_based": {
          "communication_pro": {
            "name": "Communication Pro",
            "description": "Participated in 3+ hours of meetings, oof.",
            "xp_reward": 200,
            "threshold_hours": 3,
          },
        },
      },
      "level_system": {"xp_per_level": 100, "max_level": 100},
      "monitoring": {
        "poll_interval_seconds": 30,
        "idle_threshold_minutes": 1,
        "minimum_activity_seconds": 10,
        "stats_display_interval_minutes": 10,
      },
      "logging": {"level": "INFO", "max_file_size_mb": 10, "max_files": 5, "log_directory": "logs"},
    };
  }

  void _watchConfigFile() {
    // Check for config file changes every 5 seconds
    Timer.periodic(Duration(seconds: 5), (timer) async {
      try {
        if (_configFile != null && await _configFile!.exists()) {
          final lastModified = await _configFile!.lastModified();
          if (_lastModified == null || lastModified.isAfter(_lastModified!)) {
            Logger.info('Configuration file changed, reloading...');
            await _loadConfig();
          }
        }
      } catch (e) {
        Logger.error('Error checking config file: $e');
      }
    });
  }

  // Getters for different config sections
  Map<String, dynamic> get xpRewards {
    _ensureInitialized();
    return _config!['xp_rewards'] ?? {};
  }
  
  Map<String, dynamic> get achievements {
    _ensureInitialized();
    return _config!['achievements'] ?? {};
  }
  
  Map<String, dynamic> get levelSystem {
    _ensureInitialized();
    return _config!['level_system'] ?? {};
  }
  
  Map<String, dynamic> get monitoring {
    _ensureInitialized();
    return _config!['monitoring'] ?? {};
  }
  
  Map<String, dynamic> get logging {
    _ensureInitialized();
    return _config!['logging'] ?? {};
  }
  
  Map<String, dynamic> get overlay {
    _ensureInitialized();
    return _config!['overlay'] ?? {
      "enabled": true,
      "app_path": "",
      "duration_seconds": 3,
    };
  }

  // Specific getters for commonly used values
  int getBaseXP(String activityType) {
    return xpRewards['base_multipliers']?[activityType] ?? 1;
  }

  double getTimeMultiplier(DateTime time) {
    final hour = time.hour;
    final timeStr = '${hour.toString().padLeft(2, '0')}:00';

    // Check deep work hours
    final deepWorkTimes = xpRewards['time_multipliers']?['deep_work_hours']?['times'] as List?;
    if (deepWorkTimes != null) {
      for (final timeRange in deepWorkTimes) {
        if (_isTimeInRange(timeStr, timeRange)) {
          return (xpRewards['time_multipliers']['deep_work_hours']['multiplier'] ?? 1.0).toDouble();
        }
      }
    }

    // Check late night penalty
    final lateNightTimes = xpRewards['time_multipliers']?['late_night_penalty']?['times'] as List?;
    if (lateNightTimes != null) {
      for (final timeRange in lateNightTimes) {
        if (_isTimeInRange(timeStr, timeRange)) {
          return (xpRewards['time_multipliers']['late_night_penalty']['multiplier'] ?? 1.0).toDouble();
        }
      }
    }

    return 1.0;
  }

  bool _isTimeInRange(String currentTime, String range) {
    final parts = range.split('-');
    if (parts.length != 2) return false;

    final start = parts[0];
    final end = parts[1];

    // Simple time comparison (assumes same day)
    return currentTime.compareTo(start) >= 0 && currentTime.compareTo(end) <= 0;
  }

  int getFocusSessionBonus(int minutes) {
    final baseXP = (xpRewards['focus_session_bonuses']?['base_xp_per_minute'] ?? 5) * minutes;
    final milestones = xpRewards['focus_session_bonuses']?['milestones'] as Map<String, dynamic>? ?? {};

    int bonus = 0;
    for (final entry in milestones.entries) {
      final threshold = int.tryParse(entry.key) ?? 0;
      if (minutes >= threshold) {
        bonus += entry.value as int;
      }
    }

    return baseXP + bonus;
  }

  int getZoomXP(String status, int minutes) {
    final multiplier = xpRewards['zoom_multipliers']?[status] ?? 0;
    return (minutes * multiplier).toInt();
  }

  int getXPPerLevel() {
    return levelSystem['xp_per_level'] ?? 100;
  }

  int calculateLevel(int totalXP) {
    return (totalXP / getXPPerLevel()).floor() + 1;
  }
  
  // Overlay configuration getters
  String? getOverlayAppPath() {
    return overlay['app_path'] as String?;
  }
  
  bool isOverlayEnabled() {
    return overlay['enabled'] as bool? ?? true;
  }
  
  int getOverlayDuration() {
    return overlay['duration_seconds'] as int? ?? 3;
  }

  // Update configuration programmatically
  Future<void> updateConfig(String path, dynamic value) async {
    try {
      _ensureInitialized();
      _setNestedValue(_config!, path.split('.'), value);
      await _saveConfig();
      Logger.info('Configuration updated: $path = $value');
    } catch (e) {
      Logger.error('Failed to update configuration: $e');
    }
  }

  void _setNestedValue(Map<String, dynamic> map, List<String> path, dynamic value) {
    if (path.length == 1) {
      map[path[0]] = value;
      return;
    }

    final key = path[0];
    if (!map.containsKey(key) || map[key] is! Map<String, dynamic>) {
      map[key] = <String, dynamic>{};
    }

    _setNestedValue(map[key], path.sublist(1), value);
  }

  Future<void> _saveConfig() async {
    try {
      if (_configFile != null) {
        await _configFile!.writeAsString(jsonEncode(_config));
        _lastModified = await _configFile!.lastModified();
      }
    } catch (e) {
      Logger.error('Failed to save configuration: $e');
    }
  }

  Map<String, dynamic> getAllConfig() {
    _ensureInitialized();
    return Map.from(_config!);
  }
}
