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('Deep Idle Event 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('should end current activity and award XP when user goes deep idle', () async {
      // Start the monitor
      monitor.start();
      await Future.delayed(Duration(milliseconds: 10));

      print('\n🧪 Testing deep idle behavior...');

      // Start a coding activity
      mockActivityDetector.simulateActivity('vscode', 'main.dart - TestProject');
      await Future.delayed(Duration(milliseconds: 10));
      
      // Work for 30 minutes
      mockTimeProvider.advanceTime(Duration(minutes: 30));
      
      // Check that no activity has been saved yet (still in progress)
      var stats = monitor.getTodayStats();
      var initialXP = stats['xp'] as int;
      print('📊 Initial XP before deep idle: $initialXP');

      // User goes deep idle - this should trigger ending the current activity
      print('😴 User goes deep idle...');
      mockIdleMonitor.simulateDeepIdle();
      await Future.delayed(Duration(milliseconds: 50)); // Allow event processing

      // Check that the activity was saved and XP was awarded
      stats = monitor.getTodayStats();
      var finalXP = stats['xp'] as int;
      var focusTime = stats['focus_time'] as int;
      
      print('📊 Final XP after deep idle: $finalXP');
      print('📊 Focus time: ${(focusTime / 60).toStringAsFixed(1)} minutes');

      // Verify that XP was awarded for the 30-minute coding session
      expect(finalXP, greaterThan(initialXP), 
        reason: 'Should have earned XP from the coding session when going deep idle');
      
      // Expected: 30 minutes * 10 XP/min = 300 XP (base, before multipliers)
      expect(finalXP, greaterThan(200), 
        reason: 'Should have earned substantial XP from 30 minutes of coding');
      
      // Should have focus time from coding
      expect(focusTime, greaterThan(25 * 60), 
        reason: 'Should have at least 25 minutes of focus time recorded');

      print('✅ Deep idle activity ending test passed!');
    });

    test('should not duplicate XP when going from light idle to deep idle', () async {
      // Start the monitor
      monitor.start();
      await Future.delayed(Duration(milliseconds: 10));

      print('\n🧪 Testing light idle to deep idle transition...');

      // Start a coding activity
      mockActivityDetector.simulateActivity('vscode', 'feature.dart');
      await Future.delayed(Duration(milliseconds: 10));
      
      // Work for 20 minutes
      mockTimeProvider.advanceTime(Duration(minutes: 20));
      
      // User goes light idle first
      print('😐 User goes light idle...');
      mockIdleMonitor.simulateLightIdle();
      await Future.delayed(Duration(milliseconds: 50));

      var stats = monitor.getTodayStats();
      var xpAfterLightIdle = stats['xp'] as int;
      print('📊 XP after light idle: $xpAfterLightIdle');

      // Then user goes deep idle
      print('😴 User goes deep idle...');
      mockIdleMonitor.simulateDeepIdle();
      await Future.delayed(Duration(milliseconds: 50));

      stats = monitor.getTodayStats();
      var xpAfterDeepIdle = stats['xp'] as int;
      print('📊 XP after deep idle: $xpAfterDeepIdle');

      // XP should have been awarded when going deep idle, but not duplicated
      expect(xpAfterDeepIdle, greaterThan(0), 
        reason: 'Should have earned XP from the coding session');
      
      // The XP should be the same whether we went through light idle or not
      // (since the activity should only be saved once when going deep idle)
      expect(xpAfterDeepIdle, greaterThan(150), 
        reason: 'Should have earned XP for 20 minutes of coding');

      print('✅ Light idle to deep idle transition test passed!');
    });

    test('should handle multiple activity sessions with deep idle interruptions', () async {
      // Start the monitor
      monitor.start();
      await Future.delayed(Duration(milliseconds: 10));

      print('\n🧪 Testing multiple sessions with deep idle interruptions...');

      // First coding session
      mockActivityDetector.simulateActivity('vscode', 'session1.dart');
      await Future.delayed(Duration(milliseconds: 10));
      mockTimeProvider.advanceTime(Duration(minutes: 25));
      
      // Go deep idle (should end first session)
      mockIdleMonitor.simulateDeepIdle();
      await Future.delayed(Duration(milliseconds: 50));
      
      var stats = monitor.getTodayStats();
      var xpAfterFirstSession = stats['xp'] as int;
      print('📊 XP after first session: $xpAfterFirstSession');

      // User becomes active again
      mockIdleMonitor.simulateActive();
      await Future.delayed(Duration(milliseconds: 10));

      // Second coding session
      mockActivityDetector.simulateActivity('vscode', 'session2.dart');
      await Future.delayed(Duration(milliseconds: 10));
      mockTimeProvider.advanceTime(Duration(minutes: 35));
      
      // Go deep idle again (should end second session)
      mockIdleMonitor.simulateDeepIdle();
      await Future.delayed(Duration(milliseconds: 50));
      
      stats = monitor.getTodayStats();
      var finalXP = stats['xp'] as int;
      var totalFocusTime = stats['focus_time'] as int;
      
      print('📊 Final XP after both sessions: $finalXP');
      print('📊 Total focus time: ${(totalFocusTime / 60).toStringAsFixed(1)} minutes');

      // Should have XP from both sessions
      expect(finalXP, greaterThan(xpAfterFirstSession), 
        reason: 'Should have earned additional XP from second session');
      
      // Should have substantial XP from 60 minutes total (25 + 35)
      expect(finalXP, greaterThan(400), 
        reason: 'Should have earned substantial XP from both coding sessions');
      
      // Should have focus time from both sessions (at least 55 minutes)
      expect(totalFocusTime, greaterThan(55 * 60), 
        reason: 'Should have focus time from both sessions');

      print('✅ Multiple sessions with deep idle test passed!');
    });
  });
}
