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

void main() {
  group('Simple Productivity 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 testable monitor with mocked dependencies
      monitor = ProductivityMonitor(
        db: db,
        idleMonitor: mockIdleMonitor,
        activityDetector: mockActivityDetector,
        timeProvider: mockTimeProvider,
        desktopEnhancer: mockDesktopEnhancer,
      );
    });

    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 basic coding session with XP calculation', () async {
      // Start the monitor
      monitor.start();
      await Future.delayed(Duration(milliseconds: 10));

      print('\n💻 Starting coding session...');

      // Simulate 1 hour of coding
      mockActivityDetector.simulateActivity('vscode', 'main.dart - TestProject');
      await Future.delayed(Duration(milliseconds: 1)); // Allow event to be processed
      mockTimeProvider.advanceTime(Duration(minutes: 60));
      monitor.flushCurrentActivity();

      // Check stats
      final stats = monitor.getTodayStats();
      print(
        '📊 Stats: ${stats['xp']} XP, Level ${stats['level']}, ${(stats['focus_time'] / 3600).toStringAsFixed(1)}h focus',
      );

      // Verify XP was earned
      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');
      expect(stats['level'], greaterThanOrEqualTo(1), reason: 'Should have at least level 1');

      // Expected: 60 minutes * 10 XP/min = 600 XP (plus any time multipliers)
      expect(stats['xp'], greaterThan(500), reason: 'Should have substantial XP from 1 hour coding');

      print('✅ Basic coding session test passed!');
    });

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

      print('\n🔄 Simulating mixed activity day...');

      // Morning coding (2 hours)
      mockActivityDetector.simulateActivity('vscode', 'feature.dart');
      await Future.delayed(Duration(milliseconds: 1));
      mockTimeProvider.advanceTime(Duration(minutes: 120));
      monitor.flushCurrentActivity();

      // Meeting (1 hour)
      mockActivityDetector.simulateActivity('zoom', 'Team Meeting');
      await Future.delayed(Duration(milliseconds: 1));
      mockTimeProvider.advanceTime(Duration(minutes: 60));
      monitor.flushCurrentActivity();

      // Research (30 minutes)
      mockActivityDetector.simulateActivity('firefox', 'Documentation - dart.dev');
      await Future.delayed(Duration(milliseconds: 1));
      mockTimeProvider.advanceTime(Duration(minutes: 30));
      monitor.flushCurrentActivity();

      final stats = monitor.getTodayStats();
      print('📊 Mixed day stats: ${stats['xp']} XP, Level ${stats['level']}');
      print(
        '   Focus: ${(stats['focus_time'] / 3600).toStringAsFixed(1)}h, Meetings: ${(stats['meeting_time'] / 3600).toStringAsFixed(1)}h',
      );

      // Verify different activity types
      expect(stats['xp'], greaterThan(1000), reason: 'Should have substantial XP from mixed activities');
      expect(stats['focus_time'], greaterThan(0), reason: 'Should have focus time from coding and research');
      expect(stats['meeting_time'], greaterThan(0), reason: 'Should have meeting time from zoom');

      print('✅ Mixed activity day test passed!');
    });

    test('demonstrates XP calculation accuracy', () async {
      monitor.start();
      await Future.delayed(Duration(milliseconds: 10));

      print('\n🧮 Testing XP calculation accuracy...');

      // Test different activity types with known durations
      final activities = [
        ('vscode', 'coding', 30, 10), // 30 min coding at 10 XP/min = 300 XP
        ('firefox', 'research', 20, 6), // 20 min research at 6 XP/min = 120 XP
        ('slack', 'collaboration', 15, 7), // 15 min collaboration at 7 XP/min = 105 XP
        ('zoom', 'meeting', 60, 3), // 60 min meeting at 3 XP/min = 180 XP
      ];

      int expectedTotalXP = 0;

      for (final (app, description, minutes, xpPerMin) in activities) {
        mockActivityDetector.simulateActivity(app, description);
        await Future.delayed(Duration(milliseconds: 1));
        mockTimeProvider.advanceTime(Duration(minutes: minutes));
        monitor.flushCurrentActivity();

        expectedTotalXP += minutes * xpPerMin;
        print('   $description: $minutes min × $xpPerMin XP/min = ${minutes * xpPerMin} XP');
      }

      final stats = monitor.getTodayStats();
      final actualXP = stats['xp'] as int;

      print('📊 Expected: ~$expectedTotalXP XP, Actual: $actualXP XP');

      // Allow for time multipliers (should be close to expected)
      expect(actualXP, greaterThan(expectedTotalXP * 0.8), reason: 'XP should be reasonably close to expected');
      expect(actualXP, lessThan(expectedTotalXP * 2.0), reason: 'XP should not be wildly inflated');

      print('✅ XP calculation accuracy test passed!');
    });

    test('verifies level progression', () async {
      monitor.start();
      await Future.delayed(Duration(milliseconds: 10));

      print('\n📈 Testing level progression...');

      // Simulate enough activity to level up (need 100+ XP per level)
      for (int i = 0; i < 5; i++) {
        mockActivityDetector.simulateActivity('vscode', 'level_up_test_$i.dart');
        await Future.delayed(Duration(milliseconds: 1));
        mockTimeProvider.advanceTime(Duration(minutes: 30)); // 30 min * 10 XP/min = 300 XP
        monitor.flushCurrentActivity();

        final stats = monitor.getTodayStats();
        print('   Session ${i + 1}: ${stats['xp']} XP, Level ${stats['level']}');
      }

      final finalStats = monitor.getTodayStats();
      expect(finalStats['level'], greaterThan(1), reason: 'Should have leveled up');
      expect(finalStats['xp'], greaterThan(1000), reason: 'Should have substantial XP');

      print('✅ Level progression test passed!');
    });
  });
}
