import 'package:test/test.dart';
import 'package:sqlite3/sqlite3.dart';
import 'package:xp_nix/src/monitors/productivity_monitor.dart';
import 'package:xp_nix/src/testing/mock_idle_monitor.dart';
import 'package:xp_nix/src/testing/mock_activity_detector.dart';
import 'package:xp_nix/src/testing/mock_time_provider.dart';
import 'package:xp_nix/src/testing/mock_desktop_enhancer.dart';
import 'package:xp_nix/src/config/config_manager.dart';

void main() {
  group('Work Day Simulation Tests', () {
    late Database db;
    late ProductivityMonitor monitor;
    late MockIdleMonitor mockIdleMonitor;
    late MockActivityDetector mockActivityDetector;
    late MockTimeProvider mockTimeProvider;
    late MockDesktopEnhancer mockDesktopEnhancer;

    setUp(() async {
      // Create in-memory database for testing
      db = sqlite3.openInMemory();

      // Reset and initialize ConfigManager with default config
      ConfigManager.resetInstance();
      await ConfigManager.instance.initialize('/tmp/test_config_${DateTime.now().millisecondsSinceEpoch}.json');

      // Create mock dependencies
      mockIdleMonitor = MockIdleMonitor();
      mockActivityDetector = MockActivityDetector();
      mockTimeProvider = MockTimeProvider();
      mockDesktopEnhancer = MockDesktopEnhancer();

      // Set up starting time (Monday 9 AM)
      mockTimeProvider.setTime(DateTime(2024, 1, 1, 9, 0));

      // Create monitor with mocked dependencies
      monitor = ProductivityMonitor(
        db: db,
        idleMonitor: mockIdleMonitor,
        timeProvider: mockTimeProvider,
        desktopEnhancer: mockDesktopEnhancer,
        activityDetector: mockActivityDetector,
      );
    });

    tearDown(() async {
      monitor.stop();
      // Add a small delay to allow async operations to complete
      await Future.delayed(Duration(milliseconds: 100));
      try {
        db.dispose();
      } catch (e) {
        // Database might already be closed, ignore the error
      }
    });

    test('simulates a full productive work day', () async {
      // Start the monitor
      monitor.start();

      // Wait a moment for initialization
      await Future.delayed(Duration(milliseconds: 10));

      // === MORNING CODING SESSION (9:00 - 10:30) ===
      print('\n🌅 Starting morning coding session...');
      mockActivityDetector.simulateActivity('vscode', 'main.dart - ProductivityApp');
      mockTimeProvider.advanceTime(Duration(minutes: 90));
      monitor.flushCurrentActivity(); // Save the activity

      // Simulate switching to a different file
      mockActivityDetector.simulateActivity('vscode', 'database_manager.dart - ProductivityApp');
      mockTimeProvider.advanceTime(Duration(minutes: 30));
      monitor.flushCurrentActivity(); // Save the activity

      // Check stats after morning coding
      var stats = monitor.getTodayStats();
      expect(stats['xp'], greaterThan(0), reason: 'Should have earned XP from coding');
      expect(stats['focus_time'], greaterThan(0), reason: 'Should have focus time from coding');
      print('📊 After morning coding: ${stats['xp']} XP, ${(stats['focus_time'] / 3600).toStringAsFixed(1)}h focus');

      // === BRIEF BREAK - CHECK SLACK (10:30 - 10:45) ===
      print('\n💬 Quick Slack check...');
      mockActivityDetector.simulateActivity('slack', 'General Channel');
      mockTimeProvider.advanceTime(Duration(minutes: 15));
      monitor.flushCurrentActivity();

      // === RESEARCH SESSION (10:45 - 11:30) ===
      print('\n🔍 Research session...');
      mockActivityDetector.simulateActivity('firefox', 'Dart Documentation - dart.dev');
      mockTimeProvider.advanceTime(Duration(minutes: 45));
      monitor.flushCurrentActivity();

      // === TEAM MEETING (11:30 - 12:30) ===
      print('\n📅 Team meeting...');
      mockActivityDetector.simulateActivity('zoom', 'Weekly Team Standup');
      mockTimeProvider.advanceTime(Duration(minutes: 60));
      monitor.flushCurrentActivity();

      // Check stats after meeting
      stats = monitor.getTodayStats();
      expect(stats['meeting_time'], greaterThan(0), reason: 'Should have meeting time');
      print('📊 After meeting: ${stats['xp']} XP, ${(stats['meeting_time'] / 3600).toStringAsFixed(1)}h meetings');

      // === LUNCH BREAK - GO IDLE (12:30 - 13:30) ===
      print('\n🍽️ Lunch break - going idle...');
      mockIdleMonitor.simulateIdle();
      mockTimeProvider.advanceTime(Duration(minutes: 60));

      // Come back from lunch
      print('\n🔄 Back from lunch...');
      mockIdleMonitor.simulateActive();

      // Should get focus session bonus for the morning work
      stats = monitor.getTodayStats();
      expect(stats['focus_sessions'], greaterThan(0), reason: 'Should have focus sessions from idle recovery');
      print('📊 After lunch: ${stats['focus_sessions']} focus sessions completed');

      // === AFTERNOON CODING SPRINT (13:30 - 15:30) ===
      print('\n⚡ Afternoon coding sprint...');
      mockActivityDetector.simulateActivity('vscode', 'test_suite.dart - ProductivityApp');
      mockTimeProvider.advanceTime(Duration(minutes: 120));
      monitor.flushCurrentActivity();

      // === DOCUMENTATION WORK (15:30 - 16:30) ===
      print('\n📝 Documentation work...');
      mockActivityDetector.simulateActivity('vscode', 'README.md - ProductivityApp');
      mockTimeProvider.advanceTime(Duration(minutes: 60));
      monitor.flushCurrentActivity();

      // === END OF DAY WRAP-UP (16:30 - 17:00) ===
      print('\n📋 End of day wrap-up...');
      mockActivityDetector.simulateActivity('slack', 'Daily Summary');
      mockTimeProvider.advanceTime(Duration(minutes: 30));
      monitor.flushCurrentActivity();

      // === FINAL STATS VERIFICATION ===
      print('\n📈 Final day statistics:');
      stats = monitor.getTodayStats();
      monitor.printDetailedStats();

      // Verify XP calculations
      expect(stats['xp'], greaterThan(1000), reason: 'Should have substantial XP from full work day');
      expect(stats['level'], greaterThanOrEqualTo(2), reason: 'Should have leveled up');

      // Verify focus time (coding + research)
      final focusHours = stats['focus_time'] / 3600;
      expect(focusHours, greaterThan(4), reason: 'Should have 4+ hours of focus time');
      expect(focusHours, lessThan(6), reason: 'Focus time should be reasonable');

      // Verify meeting time
      final meetingHours = stats['meeting_time'] / 3600;
      expect(meetingHours, greaterThan(0.9), reason: 'Should have ~1 hour of meeting time');
      expect(meetingHours, lessThan(1.1), reason: 'Meeting time should be accurate');

      // Verify focus sessions
      expect(stats['focus_sessions'], greaterThanOrEqualTo(1), reason: 'Should have at least 1 focus session');

      // Test specific XP calculations
      _verifyXPCalculations(stats);

      print('\n✅ Work day simulation completed successfully!');
      print(
        '📊 Final Stats: Level ${stats['level']}, ${stats['xp']} XP, ${focusHours.toStringAsFixed(1)}h focus, ${stats['focus_sessions']} sessions',
      );
    });

    test('simulates rapid context switching day', () async {
      monitor.start();
      await Future.delayed(Duration(milliseconds: 10));

      print('\n🔄 Simulating rapid context switching...');

      // Simulate a day with lots of short activities
      final activities = [
        ('vscode', 'main.dart', 15), // 15 min coding
        ('slack', 'General', 5), // 5 min slack
        ('firefox', 'Stack Overflow', 10), // 10 min research
        ('vscode', 'test.dart', 20), // 20 min coding
        ('zoom', 'Quick sync', 15), // 15 min meeting
        ('vscode', 'bug_fix.dart', 25), // 25 min coding
        ('slack', 'Code review', 10), // 10 min collaboration
      ];

      for (final (app, title, minutes) in activities) {
        mockActivityDetector.simulateActivity(app, title);
        mockTimeProvider.advanceTime(Duration(minutes: minutes));
        monitor.flushCurrentActivity(); // Flush each activity
      }

      final stats = monitor.getTodayStats();

      // Should still accumulate reasonable XP despite context switching
      expect(stats['xp'], greaterThan(200), reason: 'Should earn XP from varied activities');
      expect(stats['focus_time'], greaterThan(0), reason: 'Should have some focus time');

      print('📊 Context switching day: ${stats['xp']} XP, ${(stats['focus_time'] / 3600).toStringAsFixed(1)}h focus');
    });

    test('simulates achievement unlocking', () async {
      monitor.start();
      await Future.delayed(Duration(milliseconds: 10));

      print('\n🏆 Testing achievement unlocking...');

      // Simulate extended coding to trigger achievements
      mockActivityDetector.simulateActivity('vscode', 'epic_feature.dart');

      // Advance time to accumulate enough XP for level 5 (need ~500 XP)
      // 30 min * 10 XP/min = 300 XP per flush, need at least 2 flushes
      for (int i = 0; i < 3; i++) {
        mockTimeProvider.advanceTime(Duration(minutes: 60)); // 1 hour each
        monitor.flushCurrentActivity();
        await Future.delayed(Duration(milliseconds: 1)); // Allow level check
      }

      final stats = monitor.getTodayStats();
      expect(stats['level'], greaterThanOrEqualTo(2), reason: 'Should reach at least level 2');
      expect(stats['xp'], greaterThan(500), reason: 'Should have substantial XP');

      print('📊 Achievement test: Level ${stats['level']}, ${stats['xp']} XP');
    });

    test('verifies idle time handling', () async {
      monitor.start();
      await Future.delayed(Duration(milliseconds: 10));

      print('\n😴 Testing idle time handling...');

      // Start with some activity and make sure user is active
      mockIdleMonitor.simulateActive(); // Ensure we start active
      mockActivityDetector.simulateActivity('vscode', 'work.dart');
      mockTimeProvider.advanceTime(Duration(minutes: 30));
      monitor.flushCurrentActivity();

      // Go idle for extended period
      mockIdleMonitor.simulateIdle();
      mockTimeProvider.advanceTime(Duration(minutes: 90)); // 1.5 hours idle

      // Come back active - this should trigger focus session calculation
      mockIdleMonitor.simulateActive();

      // Should get focus session bonus
      final stats = monitor.getTodayStats();
      expect(stats['focus_sessions'], greaterThan(0), reason: 'Should award focus session after idle period');

      print('📊 Idle handling: ${stats['focus_sessions']} focus sessions awarded');
    });
  });
}

/// Verify that XP calculations are working correctly
void _verifyXPCalculations(Map<String, dynamic> stats) {
  print('\n🧮 Verifying XP calculations...');

  // Expected XP breakdown (approximate):
  // - Coding: ~4 hours * 60 min * 10 XP/min = ~2400 XP
  // - Research: ~45 min * 6 XP/min = ~270 XP
  // - Meetings: ~60 min * 3 XP/min = ~180 XP
  // - Collaboration: ~45 min * 7 XP/min = ~315 XP
  // - Focus session bonuses: varies

  final totalXP = stats['xp'] as int;
  expect(totalXP, greaterThan(2000), reason: 'Should have substantial XP from full day');
  expect(totalXP, lessThan(5000), reason: 'XP should be reasonable, not inflated');

  print('✅ XP calculations appear correct: $totalXP total XP');
}
