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

void main() {
  group('Consolidation 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
      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('unified monitor can be created and started', () async {
      expect(() => monitor.start(), returnsNormally);
      expect(monitor.getTodayStats(), isA<Map<String, dynamic>>());
    });

    test('unified monitor processes activities correctly', () async {
      monitor.start();
      await Future.delayed(Duration(milliseconds: 10));

      // Simulate coding activity
      mockActivityDetector.simulateActivity('vscode', 'test.dart');
      await Future.delayed(Duration(milliseconds: 10)); // Allow event processing
      mockTimeProvider.advanceTime(Duration(minutes: 30));
      monitor.flushCurrentActivityForced();

      final stats = monitor.getTodayStats();
      expect(stats['xp'], greaterThan(0));
      expect(stats['focus_time'], greaterThan(0));
    });

    test('unified monitor handles level ups', () async {
      monitor.start();
      await Future.delayed(Duration(milliseconds: 10));

      // Simulate enough activity to level up
      mockActivityDetector.simulateActivity('vscode', 'big_project.dart');
      await Future.delayed(Duration(milliseconds: 10)); // Allow event processing
      mockTimeProvider.advanceTime(Duration(hours: 1));
      monitor.flushCurrentActivityForced();

      // Manually trigger level up check
      await monitor.checkForLevelUpNow();

      final stats = monitor.getTodayStats();
      expect(stats['level'], greaterThanOrEqualTo(2));

      // Verify desktop enhancer was called
      print('Desktop enhancer operations: ${mockDesktopEnhancer.operations}');
      expect(mockDesktopEnhancer.operations, isNotEmpty);
      expect(mockDesktopEnhancer.operations.any((op) => op.contains('celebrateLevelUp')), isTrue);
    });

    test('unified monitor handles idle detection', () async {
      monitor.start();
      await Future.delayed(Duration(milliseconds: 10));

      // Start active
      mockIdleMonitor.simulateActive();
      mockActivityDetector.simulateActivity('vscode', 'work.dart');
      mockTimeProvider.advanceTime(Duration(minutes: 30));
      monitor.flushCurrentActivity();

      // Go idle
      mockIdleMonitor.simulateIdle();
      mockTimeProvider.advanceTime(Duration(minutes: 90));

      // Come back active
      mockIdleMonitor.simulateActive();

      final stats = monitor.getTodayStats();
      expect(stats['focus_sessions'], greaterThan(0));
    });
  });
}
