import 'dart:io';
import 'dart:async';
import 'package:xp_nix/src/models/activity_event.dart';

import 'package:xp_nix/src/database/database_manager.dart';
import 'package:xp_nix/src/config/config_manager.dart';
import 'package:xp_nix/src/logging/logger.dart';

class XPNotificationManager {
  final DatabaseManager _dbManager;
  ConfigManager get _configManager => ConfigManager.instance;
  Timer? _statusTimer;
  bool _isEnabled = true;

  XPNotificationManager(this._dbManager);

  void start() {
    // Show persistent XP status every 5 minutes
    _statusTimer = Timer.periodic(Duration(minutes: 5), (_) => _showXPStatus());

    // Show initial status
    _showXPStatus();

    Logger.info('XP Notification Manager started');
  }

  void stop() {
    _statusTimer?.cancel();
    Logger.info('XP Notification Manager stopped');
  }

  void enable() {
    _isEnabled = true;
  }

  void disable() {
    _isEnabled = false;
  }

  /// Show persistent XP status notification
  Future<void> _showXPStatus() async {
    if (!_isEnabled) return;

    try {
      final stats = _dbManager.getTodayStats();
      final currentXP = stats['xp'] as int;
      final currentLevel = stats['level'] as int;
      final focusHours = ((stats['focus_time'] as int) / 3600).toStringAsFixed(1);
      final meetingHours = ((stats['meeting_time'] as int) / 3600).toStringAsFixed(1);
      final focusSessions = stats['focus_sessions'] as int;

      // Calculate progress to next level
      final xpPerLevel = _configManager.getXPPerLevel();
      final xpInCurrentLevel = currentXP % xpPerLevel;
      final progressPercent = ((xpInCurrentLevel / xpPerLevel) * 100).round();

      final message =
          'Level $currentLevel • ${xpInCurrentLevel}/${xpPerLevel} XP\n'
          'Focus: ${focusHours}h • Meetings: ${meetingHours}h • Sessions: $focusSessions';

      await _sendNotification(
        message: message,
        progressPercent: progressPercent,
        expireTime: 300000, // 5 minutes
        urgency: 'low',
      );
    } catch (e) {
      Logger.error('Failed to show XP status: $e');
    }
  }

  /// Show XP gain notification when XP is earned
  Future<void> showXPGain({
    required String source,
    required int xpGained,
    required ActivityEvent activity,
    int? durationMinutes,
    Map<String, dynamic>? metadata,
  }) async {
    if (!_isEnabled) return;

    try {
      final stats = _dbManager.getTodayStats();
      final currentXP = stats['xp'] as int;
      final currentLevel = stats['level'] as int;

      // Calculate progress to next level
      final xpPerLevel = _configManager.getXPPerLevel();
      final xpInCurrentLevel = currentXP % xpPerLevel;
      final progressPercent = ((xpInCurrentLevel / xpPerLevel) * 100).round();

      String message = _formatXPGainMessage(source, xpGained, activity.type.displayName, durationMinutes, metadata);
      message += '\nLevel $currentLevel • $xpInCurrentLevel/$xpPerLevel XP';

      await _sendNotification(
        message: message,
        progressPercent: progressPercent,
        expireTime: 5000, // 5 seconds
        urgency: 'normal',
      );

      Logger.logXPGain(source, xpGained, activity.type.displayName, currentXP, currentLevel);
    } catch (e) {
      Logger.error('Failed to show XP gain notification: $e');
    }
  }

  /// Show level up notification
  Future<void> showLevelUp({required int newLevel, required int totalXP, required Map<String, dynamic> stats}) async {
    if (!_isEnabled) return;

    try {
      final focusHours = ((stats['focus_time'] as int) / 3600).toStringAsFixed(1);
      final meetingHours = ((stats['meeting_time'] as int) / 3600).toStringAsFixed(1);

      final message =
          '🎉 LEVEL UP! Welcome to Level $newLevel! 🎉\n'
          'Total XP: $totalXP\n'
          'Focus: ${focusHours}h • Meetings: ${meetingHours}h';

      await _sendNotification(
        message: message,
        progressPercent: 0, // Just leveled up, start fresh
        expireTime: 10000, // 10 seconds
        urgency: 'critical',
      );

      Process.run('mpv', ['~/source/non-work/xp_nix/assets/levelup.mp3']).ignore();

      Logger.info('Level up notification sent for level $newLevel');
    } catch (e) {
      Logger.error('Failed to show level up notification: $e');
    }
  }

  /// Show achievement notification
  Future<void> showAchievement({
    required String name,
    required String description,
    required int xpReward,
    required int currentLevel,
  }) async {
    if (!_isEnabled) return;

    try {
      final message =
          '🏆 Achievement Unlocked!\n'
          '$name\n'
          '$description\n'
          '+$xpReward XP';

      final stats = _dbManager.getTodayStats();
      final currentXP = stats['xp'] as int;
      final xpPerLevel = _configManager.getXPPerLevel();
      final xpInCurrentLevel = currentXP % xpPerLevel;
      final progressPercent = ((xpInCurrentLevel / xpPerLevel) * 100).round();

      await _sendNotification(
        message: message,
        progressPercent: progressPercent,
        expireTime: 8000, // 8 seconds
        urgency: 'normal',
      );

      Logger.info('Achievement notification sent: $name');
    } catch (e) {
      Logger.error('Failed to show achievement notification: $e');
    }
  }

  /// Show focus session completion notification
  Future<void> showFocusSession({
    required int durationMinutes,
    required int bonusXP,
    required String sessionType,
  }) async {
    if (!_isEnabled) return;

    try {
      String emoji = '🎯';
      String prefix = 'Focus session complete';

      if (durationMinutes >= 180) {
        emoji = '🔥';
        prefix = 'LEGENDARY FOCUS';
      } else if (durationMinutes >= 120) {
        emoji = '⚡';
        prefix = 'EPIC FOCUS';
      } else if (durationMinutes >= 60) {
        emoji = '💪';
        prefix = 'POWER FOCUS';
      }

      final message =
          '$emoji $prefix!\n'
          '${durationMinutes} minutes • +$bonusXP XP\n'
          'Session type: $sessionType';

      final stats = _dbManager.getTodayStats();
      final currentXP = stats['xp'] as int;
      final xpPerLevel = _configManager.getXPPerLevel();
      final xpInCurrentLevel = currentXP % xpPerLevel;
      final progressPercent = ((xpInCurrentLevel / xpPerLevel) * 100).round();

      await _sendNotification(
        message: message,
        progressPercent: progressPercent,
        expireTime: 6000, // 6 seconds
        urgency: 'normal',
      );

      Logger.info('Focus session notification sent: ${durationMinutes}min, +${bonusXP}XP');
    } catch (e) {
      Logger.error('Failed to show focus session notification: $e');
    }
  }

  String _formatXPGainMessage(
    String source,
    int xpGained,
    String activity,
    int? durationMinutes,
    Map<String, dynamic>? metadata,
  ) {
    switch (source) {
      case 'activity':
        final duration = durationMinutes != null ? ' (${durationMinutes}m)' : '';
        return '+$xpGained XP from $activity$duration';

      case 'focus_session':
        return '+$xpGained XP from focus session ($activity)';

      case 'meeting':
        final duration = durationMinutes != null ? ' (${durationMinutes}m)' : '';
        return '+$xpGained XP from meeting$duration';

      case 'achievement':
        return '+$xpGained XP from achievement: $activity';

      case 'manual_boost':
        return '+$xpGained XP manual boost: $activity';

      case 'time_multiplier':
        final multiplier = metadata?['multiplier'] ?? 1.0;
        return '+$xpGained XP from $activity (${multiplier}x bonus)';

      default:
        return '+$xpGained XP from $activity';
    }
  }

  Future<void> _sendNotification({
    required String message,
    required int progressPercent,
    required int expireTime,
    required String urgency,
  }) async {
    try {
      // Clamp progress percent to valid range
      final validProgress = progressPercent.clamp(0, 100);

      final result = await Process.run('notify-send', [
        '-h',
        'int:value:$validProgress',
        '-h',
        'string:synchronous:xp-nix',
        '-t',
        expireTime.toString(),
        '-u',
        urgency,
        'XP Nix',
        message,
      ]);

      if (result.exitCode != 0) {
        Logger.error('notify-send failed: ${result.stderr}');
      }
    } catch (e) {
      Logger.error('Failed to send notification: $e');
    }
  }

  /// Get current XP status for external queries
  Map<String, dynamic> getCurrentStatus() {
    final stats = _dbManager.getTodayStats();
    final currentXP = stats['xp'] as int;
    final currentLevel = stats['level'] as int;
    final xpPerLevel = _configManager.getXPPerLevel();
    final xpInCurrentLevel = currentXP % xpPerLevel;
    final progressPercent = ((xpInCurrentLevel / xpPerLevel) * 100).round();

    return {
      'level': currentLevel,
      'xp': currentXP,
      'xp_in_level': xpInCurrentLevel,
      'xp_per_level': xpPerLevel,
      'progress_percent': progressPercent,
      'focus_time': stats['focus_time'],
      'meeting_time': stats['meeting_time'],
      'focus_sessions': stats['focus_sessions'],
    };
  }
}
