import 'dart:async';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import '../../config/dashboard_config.dart';

/// Moniteur de performances avancé pour le Dashboard
class DashboardPerformanceMonitor {
  static const String _channelName = 'dashboard_performance';
  static const MethodChannel _channel = MethodChannel(_channelName);
  
  Timer? _monitoringTimer;
  Timer? _reportTimer;
  final List<PerformanceSnapshot> _snapshots = [];
  final StreamController<PerformanceMetrics> _metricsController = 
      StreamController<PerformanceMetrics>.broadcast();
  final StreamController<PerformanceAlert> _alertController = 
      StreamController<PerformanceAlert>.broadcast();
  
  bool _isMonitoring = false;
  DateTime _startTime = DateTime.now();
  int _alertsGeneratedCount = 0;

  // Seuils d'alerte configurables
  final double _memoryThreshold = DashboardConfig.getAlertThreshold('memoryUsage');
  final double _cpuThreshold = DashboardConfig.getAlertThreshold('cpuUsage');
  final int _networkLatencyThreshold = DashboardConfig.getAlertThreshold('networkLatency').toInt();
  final double _frameRateThreshold = DashboardConfig.getAlertThreshold('frameRate');
  
  // Streams publics
  Stream<PerformanceMetrics> get metricsStream => _metricsController.stream;
  Stream<PerformanceAlert> get alertStream => _alertController.stream;
  
  /// Démarre le monitoring des performances
  Future<void> startMonitoring() async {
    if (_isMonitoring) return;
    
    debugPrint('🔍 Démarrage du monitoring des performances...');
    
    _isMonitoring = true;
    _startTime = DateTime.now();
    
    // Timer pour collecter les métriques
    _monitoringTimer = Timer.periodic(
      DashboardConfig.performanceCheckInterval,
      (_) => _collectMetrics(),
    );
    
    // Timer pour générer les rapports
    _reportTimer = Timer.periodic(
      const Duration(minutes: 5),
      (_) => _generateReport(),
    );
    
    // Collecte initiale
    await _collectMetrics();
    
    debugPrint('✅ Monitoring des performances démarré');
  }
  
  /// Arrête le monitoring
  void stopMonitoring() {
    if (!_isMonitoring) return;
    
    _isMonitoring = false;
    _monitoringTimer?.cancel();
    _reportTimer?.cancel();
    
    debugPrint('🛑 Monitoring des performances arrêté');
  }
  
  /// Collecte les métriques de performance
  Future<void> _collectMetrics() async {
    try {
      final metrics = await _gatherMetrics();
      final snapshot = PerformanceSnapshot(
        timestamp: DateTime.now(),
        metrics: metrics,
      );
      
      _snapshots.add(snapshot);
      
      // Garder seulement les 1000 derniers snapshots
      if (_snapshots.length > 1000) {
        _snapshots.removeAt(0);
      }
      
      // Émettre les métriques
      _metricsController.add(metrics);
      
      // Vérifier les seuils d'alerte
      _checkAlerts(metrics);
      
    } catch (e) {
      debugPrint('❌ Erreur lors de la collecte des métriques: $e');
    }
  }
  
  /// Rassemble toutes les métriques
  Future<PerformanceMetrics> _gatherMetrics() async {
    final memoryUsage = await _getMemoryUsage();
    final cpuUsage = await _getCpuUsage();
    final networkLatency = await _getNetworkLatency();
    final frameRate = await _getFrameRate();
    final batteryLevel = await _getBatteryLevel();
    final diskUsage = await _getDiskUsage();
    final networkUsage = await _getNetworkUsage();
    
    return PerformanceMetrics(
      timestamp: DateTime.now(),
      memoryUsage: memoryUsage,
      cpuUsage: cpuUsage,
      networkLatency: networkLatency,
      frameRate: frameRate,
      batteryLevel: batteryLevel,
      diskUsage: diskUsage,
      networkUsage: networkUsage,
      uptime: DateTime.now().difference(_startTime),
    );
  }
  
  /// Obtient l'utilisation mémoire
  Future<double> _getMemoryUsage() async {
    try {
      if (Platform.isAndroid || Platform.isIOS) {
        final result = await _channel.invokeMethod('getMemoryUsage');
        return (result as num).toDouble();
      } else {
        // Simulation pour les autres plateformes
        return _simulateMemoryUsage();
      }
    } catch (e) {
      return _simulateMemoryUsage();
    }
  }
  
  /// Obtient l'utilisation CPU
  Future<double> _getCpuUsage() async {
    try {
      if (Platform.isAndroid || Platform.isIOS) {
        final result = await _channel.invokeMethod('getCpuUsage');
        return (result as num).toDouble();
      } else {
        return _simulateCpuUsage();
      }
    } catch (e) {
      return _simulateCpuUsage();
    }
  }
  
  /// Obtient la latence réseau (hôte/port depuis DashboardConfig.apiBaseUrl).
  Future<int> _getNetworkLatency() async {
    try {
      final uri = Uri.parse(DashboardConfig.apiBaseUrl);
      final host = uri.host.isNotEmpty ? uri.host : 'localhost';
      final port = uri.hasPort ? uri.port : 8085;
      final stopwatch = Stopwatch()..start();
      final socket = await Socket.connect(host, port).timeout(const Duration(seconds: 5));
      stopwatch.stop();
      await socket.close();
      return stopwatch.elapsedMilliseconds;
    } catch (e) {
      return _simulateNetworkLatency();
    }
  }
  
  /// Obtient le frame rate
  Future<double> _getFrameRate() async {
    try {
      if (Platform.isAndroid || Platform.isIOS) {
        final result = await _channel.invokeMethod('getFrameRate');
        return (result as num).toDouble();
      } else {
        return _simulateFrameRate();
      }
    } catch (e) {
      return _simulateFrameRate();
    }
  }
  
  /// Obtient le niveau de batterie
  Future<double> _getBatteryLevel() async {
    try {
      if (Platform.isAndroid || Platform.isIOS) {
        final result = await _channel.invokeMethod('getBatteryLevel');
        return (result as num).toDouble();
      } else {
        return _simulateBatteryLevel();
      }
    } catch (e) {
      return _simulateBatteryLevel();
    }
  }
  
  /// Obtient l'utilisation disque
  Future<double> _getDiskUsage() async {
    try {
      if (Platform.isAndroid || Platform.isIOS) {
        final result = await _channel.invokeMethod('getDiskUsage');
        return (result as num).toDouble();
      } else {
        return _simulateDiskUsage();
      }
    } catch (e) {
      return _simulateDiskUsage();
    }
  }
  
  /// Obtient l'utilisation réseau
  Future<NetworkUsage> _getNetworkUsage() async {
    try {
      if (Platform.isAndroid || Platform.isIOS) {
        final result = await _channel.invokeMethod('getNetworkUsage');
        return NetworkUsage(
          bytesReceived: (result['bytesReceived'] as num).toDouble(),
          bytesSent: (result['bytesSent'] as num).toDouble(),
        );
      } else {
        return _simulateNetworkUsage();
      }
    } catch (e) {
      return _simulateNetworkUsage();
    }
  }
  
  /// Vérifie les seuils d'alerte
  void _checkAlerts(PerformanceMetrics metrics) {
    // Alerte mémoire
    if (metrics.memoryUsage > _memoryThreshold) {
      _alertsGeneratedCount++;
      _alertController.add(PerformanceAlert(
        type: AlertType.memory,
        severity: AlertSeverity.warning,
        message: 'Utilisation mémoire élevée: ${metrics.memoryUsage.toStringAsFixed(1)}MB',
        value: metrics.memoryUsage,
        threshold: _memoryThreshold,
        timestamp: DateTime.now(),
      ));
    }
    
    // Alerte CPU
    if (metrics.cpuUsage > _cpuThreshold) {
      _alertsGeneratedCount++;
      _alertController.add(PerformanceAlert(
        type: AlertType.cpu,
        severity: AlertSeverity.warning,
        message: 'Utilisation CPU élevée: ${metrics.cpuUsage.toStringAsFixed(1)}%',
        value: metrics.cpuUsage,
        threshold: _cpuThreshold,
        timestamp: DateTime.now(),
      ));
    }
    
    // Alerte latence réseau
    if (metrics.networkLatency > _networkLatencyThreshold) {
      _alertsGeneratedCount++;
      _alertController.add(PerformanceAlert(
        type: AlertType.network,
        severity: AlertSeverity.error,
        message: 'Latence réseau élevée: ${metrics.networkLatency}ms',
        value: metrics.networkLatency.toDouble(),
        threshold: _networkLatencyThreshold.toDouble(),
        timestamp: DateTime.now(),
      ));
    }
    
    // Alerte frame rate
    if (metrics.frameRate < _frameRateThreshold) {
      _alertsGeneratedCount++;
      _alertController.add(PerformanceAlert(
        type: AlertType.performance,
        severity: AlertSeverity.warning,
        message: 'Frame rate faible: ${metrics.frameRate.toStringAsFixed(1)}fps',
        value: metrics.frameRate,
        threshold: _frameRateThreshold,
        timestamp: DateTime.now(),
      ));
    }
  }
  
  /// Génère un rapport de performance
  void _generateReport() {
    if (_snapshots.isEmpty) return;
    
    final recentSnapshots = _snapshots.where((snapshot) =>
        DateTime.now().difference(snapshot.timestamp).inMinutes <= 5).toList();
    
    if (recentSnapshots.isEmpty) return;
    
    final report = PerformanceReport.fromSnapshots(recentSnapshots);
    
    debugPrint('📊 RAPPORT DE PERFORMANCE (5 min)');
    debugPrint('Mémoire: ${report.averageMemoryUsage.toStringAsFixed(1)}MB (max: ${report.maxMemoryUsage.toStringAsFixed(1)}MB)');
    debugPrint('CPU: ${report.averageCpuUsage.toStringAsFixed(1)}% (max: ${report.maxCpuUsage.toStringAsFixed(1)}%)');
    debugPrint('Latence: ${report.averageNetworkLatency.toStringAsFixed(0)}ms (max: ${report.maxNetworkLatency.toStringAsFixed(0)}ms)');
    debugPrint('FPS: ${report.averageFrameRate.toStringAsFixed(1)}fps (min: ${report.minFrameRate.toStringAsFixed(1)}fps)');
  }
  
  /// Obtient les statistiques de performance
  PerformanceStats getStats() {
    if (_snapshots.isEmpty) {
      return PerformanceStats.empty();
    }
    return PerformanceStats.fromSnapshots(_snapshots, alertsGenerated: _alertsGeneratedCount);
  }
  
  /// Méthodes de simulation pour le développement
  double _simulateMemoryUsage() {
    const base = 200.0;
    final variation = 100.0 * (DateTime.now().millisecond / 1000.0);
    return base + variation;
  }
  
  double _simulateCpuUsage() {
    const base = 30.0;
    final variation = 40.0 * (DateTime.now().second / 60.0);
    return (base + variation).clamp(0.0, 100.0);
  }
  
  int _simulateNetworkLatency() {
    const base = 150;
    final variation = (200 * (DateTime.now().millisecond / 1000.0)).round();
    return base + variation;
  }
  
  double _simulateFrameRate() {
    const base = 58.0;
    final variation = 5.0 * (DateTime.now().millisecond / 1000.0);
    return (base + variation).clamp(30.0, 60.0);
  }
  
  double _simulateBatteryLevel() {
    final elapsed = DateTime.now().difference(_startTime).inMinutes;
    return (100.0 - elapsed * 0.1).clamp(0.0, 100.0);
  }
  
  double _simulateDiskUsage() {
    return 45.0 + (10.0 * (DateTime.now().millisecond / 1000.0));
  }
  
  NetworkUsage _simulateNetworkUsage() {
    const base = 1024.0;
    final variation = 512.0 * (DateTime.now().millisecond / 1000.0);
    return NetworkUsage(
      bytesReceived: base + variation,
      bytesSent: (base + variation) * 0.3,
    );
  }
  
  /// Libère les ressources
  void dispose() {
    stopMonitoring();
    _metricsController.close();
    _alertController.close();
    _snapshots.clear();
  }
}

/// Métriques de performance
class PerformanceMetrics {
  final DateTime timestamp;
  final double memoryUsage; // MB
  final double cpuUsage; // %
  final int networkLatency; // ms
  final double frameRate; // fps
  final double batteryLevel; // %
  final double diskUsage; // %
  final NetworkUsage networkUsage;
  final Duration uptime;
  
  const PerformanceMetrics({
    required this.timestamp,
    required this.memoryUsage,
    required this.cpuUsage,
    required this.networkLatency,
    required this.frameRate,
    required this.batteryLevel,
    required this.diskUsage,
    required this.networkUsage,
    required this.uptime,
  });
}

/// Utilisation réseau
class NetworkUsage {
  final double bytesReceived;
  final double bytesSent;
  
  const NetworkUsage({
    required this.bytesReceived,
    required this.bytesSent,
  });
  
  double get totalBytes => bytesReceived + bytesSent;
}

/// Snapshot de performance
class PerformanceSnapshot {
  final DateTime timestamp;
  final PerformanceMetrics metrics;
  
  const PerformanceSnapshot({
    required this.timestamp,
    required this.metrics,
  });
}

/// Alerte de performance
class PerformanceAlert {
  final AlertType type;
  final AlertSeverity severity;
  final String message;
  final double value;
  final double threshold;
  final DateTime timestamp;
  
  const PerformanceAlert({
    required this.type,
    required this.severity,
    required this.message,
    required this.value,
    required this.threshold,
    required this.timestamp,
  });
}

/// Type d'alerte
enum AlertType { memory, cpu, network, performance, battery, disk }

/// Sévérité d'alerte
enum AlertSeverity { info, warning, error, critical }

/// Rapport de performance
class PerformanceReport {
  final DateTime startTime;
  final DateTime endTime;
  final double averageMemoryUsage;
  final double maxMemoryUsage;
  final double averageCpuUsage;
  final double maxCpuUsage;
  final double averageNetworkLatency;
  final double maxNetworkLatency;
  final double averageFrameRate;
  final double minFrameRate;
  
  const PerformanceReport({
    required this.startTime,
    required this.endTime,
    required this.averageMemoryUsage,
    required this.maxMemoryUsage,
    required this.averageCpuUsage,
    required this.maxCpuUsage,
    required this.averageNetworkLatency,
    required this.maxNetworkLatency,
    required this.averageFrameRate,
    required this.minFrameRate,
  });
  
  factory PerformanceReport.fromSnapshots(List<PerformanceSnapshot> snapshots) {
    if (snapshots.isEmpty) {
      throw ArgumentError('Cannot create report from empty snapshots');
    }
    
    final metrics = snapshots.map((s) => s.metrics).toList();
    
    return PerformanceReport(
      startTime: snapshots.first.timestamp,
      endTime: snapshots.last.timestamp,
      averageMemoryUsage: metrics.map((m) => m.memoryUsage).reduce((a, b) => a + b) / metrics.length,
      maxMemoryUsage: metrics.map((m) => m.memoryUsage).reduce((a, b) => a > b ? a : b),
      averageCpuUsage: metrics.map((m) => m.cpuUsage).reduce((a, b) => a + b) / metrics.length,
      maxCpuUsage: metrics.map((m) => m.cpuUsage).reduce((a, b) => a > b ? a : b),
      averageNetworkLatency: metrics.map((m) => m.networkLatency.toDouble()).reduce((a, b) => a + b) / metrics.length,
      maxNetworkLatency: metrics.map((m) => m.networkLatency.toDouble()).reduce((a, b) => a > b ? a : b),
      averageFrameRate: metrics.map((m) => m.frameRate).reduce((a, b) => a + b) / metrics.length,
      minFrameRate: metrics.map((m) => m.frameRate).reduce((a, b) => a < b ? a : b),
    );
  }
}

/// Statistiques de performance
class PerformanceStats {
  final int totalSnapshots;
  final Duration totalUptime;
  final double averageMemoryUsage;
  final double peakMemoryUsage;
  final double averageCpuUsage;
  final double peakCpuUsage;
  final int alertsGenerated;
  
  const PerformanceStats({
    required this.totalSnapshots,
    required this.totalUptime,
    required this.averageMemoryUsage,
    required this.peakMemoryUsage,
    required this.averageCpuUsage,
    required this.peakCpuUsage,
    required this.alertsGenerated,
  });
  
  factory PerformanceStats.empty() {
    return const PerformanceStats(
      totalSnapshots: 0,
      totalUptime: Duration.zero,
      averageMemoryUsage: 0.0,
      peakMemoryUsage: 0.0,
      averageCpuUsage: 0.0,
      peakCpuUsage: 0.0,
      alertsGenerated: 0,
    );
  }
  
  factory PerformanceStats.fromSnapshots(List<PerformanceSnapshot> snapshots, {int alertsGenerated = 0}) {
    if (snapshots.isEmpty) return PerformanceStats.empty();
    
    final metrics = snapshots.map((s) => s.metrics).toList();
    
    return PerformanceStats(
      totalSnapshots: snapshots.length,
      totalUptime: snapshots.last.timestamp.difference(snapshots.first.timestamp),
      averageMemoryUsage: metrics.map((m) => m.memoryUsage).reduce((a, b) => a + b) / metrics.length,
      peakMemoryUsage: metrics.map((m) => m.memoryUsage).reduce((a, b) => a > b ? a : b),
      averageCpuUsage: metrics.map((m) => m.cpuUsage).reduce((a, b) => a + b) / metrics.length,
      peakCpuUsage: metrics.map((m) => m.cpuUsage).reduce((a, b) => a > b ? a : b),
      alertsGenerated: alertsGenerated,
    );
  }
}
