import 'dart:async';
import 'dart:convert';
import 'dart:io';
import '../interfaces/i_idle_monitor.dart';

/// Sway-specific idle monitor using swayidle
class SwayIdleMonitor implements IIdleMonitor {
  static const String _idleLightStartKey = 'SWAY_IDLE_LIGHT_START';
  static const String _idleDeepStartKey = 'SWAY_IDLE_DEEP_START';
  static const String _idleEndKey = 'SWAY_IDLE_END';

  Process? _swayidleProcess;
  final StreamController<IdleStatus> _idleStateController = StreamController<IdleStatus>.broadcast();
  IdleStatus _currentIdleStatus = IdleStatus.active;

  @override
  Stream<IdleStatus> get idleStateStream => _idleStateController.stream;

  @override
  IdleStatus get status => _currentIdleStatus;

  @override
  Future<void> start() async {
    // Start in active state
    _currentIdleStatus = IdleStatus.active;
    _idleStateController.add(IdleStatus.active);

    // Build swayidle command arguments
    final swayidleArgs = [
      '-w', // Wait for command to finish before continuing
      'timeout', '20', 'echo "$_idleLightStartKey"',
      'resume', 'echo "$_idleEndKey"',
      'timeout', '120', 'echo "$_idleDeepStartKey"',
      'resume', 'echo "$_idleEndKey"',
    ];

    try {
      // Start swayidle with our configuration
      _swayidleProcess = await Process.start('swayidle', swayidleArgs);

      // Listen to swayidle output
      _swayidleProcess!.stdout
          .transform(utf8.decoder)
          .transform(LineSplitter())
          .listen(_handleSwayidleOutput);

      _swayidleProcess!.stderr
          .transform(utf8.decoder)
          .transform(LineSplitter())
          .listen((line) {
        if (line.isNotEmpty) {
          print('SwayIdle stderr: $line');
        }
      });

      print('🔄 Started Sway idle monitoring with swayidle');
    } catch (e) {
      print('❌ Failed to start swayidle: $e');
      print('   Make sure swayidle is installed and available in PATH');
      rethrow;
    }
  }

  void _handleSwayidleOutput(String line) {
    if (line.isEmpty) return;

    switch (line) {
      case String s when s.contains(_idleLightStartKey):
        _idleStateController.add(IdleStatus.lightIdle);
        _currentIdleStatus = IdleStatus.lightIdle;
        print('🌙 User went light idle (Sway)');
      case String s when s.contains(_idleDeepStartKey):
        _idleStateController.add(IdleStatus.deepIdle);
        _currentIdleStatus = IdleStatus.deepIdle;
        print('😴 User went deep idle (Sway)');
      case String s when s.contains(_idleEndKey):
        _idleStateController.add(IdleStatus.active);
        _currentIdleStatus = IdleStatus.active;
        print('⚡ User went active (Sway)');
      default:
        // Handle other swayidle output if needed
        if (line.trim().isNotEmpty) {
          print('SwayIdle output: $line');
        }
    }
  }

  @override
  void stop() {
    try {
      _swayidleProcess?.kill();
      _swayidleProcess = null;
      print('🛑 Stopped Sway idle monitoring');
    } catch (e) {
      print('Warning: Error stopping swayidle process: $e');
    }

    try {
      _idleStateController.close();
    } catch (e) {
      print('Warning: Error closing idle state controller: $e');
    }
  }

  /// Check if swayidle is available on the system
  static Future<bool> isAvailable() async {
    try {
      final result = await Process.run('which', ['swayidle']);
      return result.exitCode == 0;
    } catch (e) {
      return false;
    }
  }

  /// Get swayidle version information
  static Future<String?> getVersion() async {
    try {
      final result = await Process.run('swayidle', ['-h']);
      if (result.exitCode == 0) {
        // swayidle doesn't have a version flag, but -h should work
        return 'swayidle (available)';
      }
      return null;
    } catch (e) {
      return null;
    }
  }
}