import 'dart:async';
import 'dart:math' as math;

import 'package:battery_plus/battery_plus.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:wakelock_plus/wakelock_plus.dart';

import '../../app/theme.dart';
import '../../platform/streaming_channel.dart';
import '../../platform/streaming_preview.dart';
import '../../providers/match_rules_provider.dart';
import '../../providers/score_provider.dart';
import '../../shared/api_client.dart';
import '../../shared/regia_share.dart';
import '../../shared/models/score_state.dart';
import '../../providers/session_provider.dart';
import '../../shared/websocket_service.dart';
import '../../shared/widgets/camera_compact_metrics.dart';
import '../../shared/widgets/camera_score_controls.dart';
import '../../shared/widgets/destructive_cta.dart';
import '../../shared/widgets/end_stream_dialog.dart';
import '../../shared/widgets/live_badge.dart';
import '../../shared/widgets/screen_insets.dart';

class CameraScreen extends ConsumerStatefulWidget {
  const CameraScreen({super.key, required this.sessionId});

  final String sessionId;

  @override
  ConsumerState<CameraScreen> createState() => _CameraScreenState();
}

class _CameraScreenState extends ConsumerState<CameraScreen> {
  static const _previewKey = ValueKey<String>('camera_streaming_preview');

  Timer? _elapsedTimer;
  Timer? _telemetryTimer;
  Timer? _statsTimer;
  int _batteryLevel = 100;
  int? _lastDelta;
  int _prevHomePoints = 0;
  int _prevAwayPoints = 0;

  double _bitrateMbps = 0;
  int _fps = 0;
  String _networkType = '4G';
  int _viewerCount = 0;

  StreamSubscription<Map<String, dynamic>>? _metricsSub;
  Orientation? _lastOrientation;

  @override
  void initState() {
    super.initState();
    WakelockPlus.enable();
    _lockOrientations();
    _bootstrap();
    _readBattery();
    _elapsedTimer = Timer.periodic(const Duration(seconds: 1), (_) {
      final session = ref.read(sessionProvider).session;
      if (session?.startedAt != null) {
        ref.read(sessionProvider.notifier).setElapsed(
              DateTime.now().difference(session!.startedAt!),
            );
      }
    });
    _telemetryTimer = Timer.periodic(const Duration(seconds: 10), (_) => _sendTelemetry());
    _statsTimer = Timer.periodic(const Duration(seconds: 30), (_) => _fetchStats());
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    final orientation = MediaQuery.orientationOf(context);
    if (_lastOrientation != null && _lastOrientation != orientation) {
      WidgetsBinding.instance.addPostFrameCallback((_) async {
        await StreamingChannel.bindPreview();
      });
    }
    _lastOrientation = orientation;
  }

  Future<bool> _ensurePermissions() async {
    final camera = await Permission.camera.request();
    final mic = await Permission.microphone.request();
    if (camera.isGranted && mic.isGranted) return true;
    if (mounted) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
          content: Text('Servono permessi fotocamera e microfono per la diretta'),
        ),
      );
    }
    return false;
  }

  Future<void> _bootstrap() async {
    try {
      if (!await _ensurePermissions()) return;

      final client = ref.read(apiClientProvider);
      var session = await client.fetchSession(widget.sessionId);

      if (session.isTerminal) {
        if (mounted) {
          ScaffoldMessenger.of(context).showSnackBar(
            const SnackBar(
              content: Text('Questa diretta è già terminata'),
            ),
          );
          context.go('/matches');
        }
        return;
      }

      final match = await client.fetchMatch(session.matchId);
      ref.read(sessionProvider.notifier).setSession(session, match: match);
      if (session.score != null) {
        ref.read(scoreProvider.notifier).reset(session.score!);
      }

      // Ripresa dopo crash: la sessione resta connecting/live, riallineiamo lo stato.
      if (session.status == 'idle' || session.status == 'paused') {
        session = await client.startSession(widget.sessionId);
        ref.read(sessionProvider.notifier).setSession(session, match: match);
      }

      final ws = ref.read(websocketServiceProvider);
      await ws.connect(sessionId: widget.sessionId, deviceRole: 'camera');

      await Future<void>.delayed(const Duration(milliseconds: 300));
      await StreamingChannel.bindPreview();

      final fresh = await client.fetchSession(widget.sessionId);
      ref.read(sessionProvider.notifier).setSession(fresh, match: match);

      if (fresh.rtmpIngestUrl != null) {
        await Future<void>.delayed(const Duration(milliseconds: 500));
        await StreamingChannel.startStream(
          rtmpUrl: fresh.rtmpIngestUrl!,
          targetBitrate: fresh.targetBitrate,
          targetFps: 30,
        );
        if (mounted && fresh.canResumeBroadcast) {
          ScaffoldMessenger.of(context).showSnackBar(
            const SnackBar(
              content: Text('Diretta ripresa — stai di nuovo in onda'),
              duration: Duration(seconds: 3),
            ),
          );
        }
      }

      _metricsSub = StreamingChannel.metricsStream
          .receiveBroadcastStream()
          .map((e) => Map<String, dynamic>.from(e as Map))
          .listen((event) {
        if (event['type'] != 'metrics') return;
        final metrics = Map<String, dynamic>.from(
          (event['metrics'] as Map?)?.map((k, v) => MapEntry(k.toString(), v)) ?? {},
        );
        setState(() {
          _bitrateMbps = (metrics['bitrateKbps'] as num? ?? 0) / 1000;
          _fps = (metrics['fps'] as num?)?.toInt() ?? 0;
        });
      });
    } on PlatformException catch (e) {
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('Errore streaming: ${e.message ?? e.code}')),
        );
      }
    } catch (e) {
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('Errore avvio camera: $e')),
        );
      }
    }
  }

  Future<void> _readBattery() async {
    final level = await Battery().batteryLevel;
    if (mounted) setState(() => _batteryLevel = level);
  }

  Future<void> _sendTelemetry() async {
    try {
      await ref.read(apiClientProvider).postTelemetry(
            sessionId: widget.sessionId,
            deviceRole: 'camera',
            batteryLevel: _batteryLevel,
            networkType: _networkType,
            currentBitrate: (_bitrateMbps * 1_000_000).round(),
            fps: _fps,
          );
    } catch (_) {}
  }

  Future<void> _fetchStats() async {
    try {
      final stats = await ref.read(apiClientProvider).youtubeStats(widget.sessionId);
      if (mounted) setState(() => _viewerCount = stats.concurrentViewers);
    } catch (_) {}
  }

  Future<void> _lockOrientations() async {
    await SystemChrome.setPreferredOrientations([
      DeviceOrientation.landscapeLeft,
      DeviceOrientation.landscapeRight,
      DeviceOrientation.portraitUp,
    ]);
  }

  Future<void> _unlockOrientation() async {
    await SystemChrome.setPreferredOrientations(DeviceOrientation.values);
  }

  Future<void> _shareRegia() async {
    final match = ref.read(sessionProvider).match;
    await shareRegiaLink(
      context,
      ref,
      sessionId: widget.sessionId,
      shareSubject:
          'Regia — ${match?.teamName ?? 'Casa'} vs ${match?.opponentName ?? 'Ospiti'}',
    );
  }

  Future<void> _leaveSession() async {
    try {
      await StreamingChannel.stopStream();
    } catch (_) {}
    try {
      await ref.read(websocketServiceProvider).disconnect();
    } catch (_) {}
    if (mounted) context.go('/matches');
  }

  /// Pausa temporanea: si può riprendere la stessa sessione.
  Future<void> _interruptStream() async {
    try {
      await StreamingChannel.stopStream();
    } catch (_) {}
    try {
      await ref.read(apiClientProvider).pauseSession(widget.sessionId);
    } catch (e) {
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('Pausa sessione: $e')),
        );
      }
    }
    await _leaveSession();
  }

  /// Chiusura definitiva: sessione ended, pagina web senza player.
  Future<void> _closeStreamPermanently() async {
    if (!mounted) return;
    final ok = await confirmEndStream(context);
    if (!ok || !mounted) return;

    try {
      await StreamingChannel.stopStream();
    } catch (_) {}
    try {
      ref.read(websocketServiceProvider).sendCommand('stop_stream');
    } catch (_) {}
    try {
      await ref.read(apiClientProvider).stopSession(widget.sessionId);
    } catch (e) {
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('Chiusura sessione: $e')),
        );
      }
    }
    await _leaveSession();
  }

  void _trackScoreDelta(ScoreState score) {
    if (score.homePoints != _prevHomePoints) {
      _lastDelta = score.homePoints - _prevHomePoints;
    } else if (score.awayPoints != _prevAwayPoints) {
      _lastDelta = score.awayPoints - _prevAwayPoints;
    }
    _prevHomePoints = score.homePoints;
    _prevAwayPoints = score.awayPoints;
  }

  @override
  void dispose() {
    _elapsedTimer?.cancel();
    _telemetryTimer?.cancel();
    _statsTimer?.cancel();
    _metricsSub?.cancel();
    WakelockPlus.disable();
    _unlockOrientation();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final sessionState = ref.watch(sessionProvider);
    final score = ref.watch(scoreProvider);
    _trackScoreDelta(score);

    final match = sessionState.match;
    final homeName = match?.teamName ?? 'HOME';
    final awayName = match?.opponentName ?? 'AWAY';
    final isLandscape =
        MediaQuery.orientationOf(context) == Orientation.landscape;
    final rules = ref.watch(matchScoringRulesProvider);
    final pointsTarget = rules.pointsTarget(score.currentSet);
    // Preview unica: non viene mai smontata al cambio orientamento.
    return Scaffold(
      backgroundColor: isLandscape ? Colors.black : AppTheme.background,
      body: Stack(
        fit: StackFit.expand,
        children: [
          const Positioned.fill(
            child: NativeStreamingPreview(
              key: _previewKey,
              showGrid: true,
              platformLabel: 'LIVE',
            ),
          ),
          if (isLandscape)
            _LandscapeOverlay(
              elapsed: sessionState.elapsed,
              batteryLevel: _batteryLevel,
              homeName: homeName,
              awayName: awayName,
              score: score,
              lastDelta: _lastDelta,
              networkType: _networkType,
              bitrateMbps: _bitrateMbps,
              fps: _fps,
              viewerCount: _viewerCount,
              onShareRegia: _shareRegia,
              onInterrupt: _interruptStream,
              onCloseStream: _closeStreamPermanently,
              pointsTarget: pointsTarget,
            )
          else
            _PortraitOverlay(
              elapsed: sessionState.elapsed,
              batteryLevel: _batteryLevel,
              homeName: homeName,
              awayName: awayName,
              score: score,
              networkType: _networkType,
              bitrateMbps: _bitrateMbps,
              fps: _fps,
              viewerCount: _viewerCount,
              onShareRegia: _shareRegia,
              onInterrupt: _interruptStream,
              onCloseStream: _closeStreamPermanently,
              pointsTarget: pointsTarget,
            ),
        ],
      ),
    );
  }
}

class _PortraitOverlay extends StatelessWidget {
  const _PortraitOverlay({
    required this.elapsed,
    required this.batteryLevel,
    required this.homeName,
    required this.awayName,
    required this.score,
    required this.networkType,
    required this.bitrateMbps,
    required this.fps,
    required this.viewerCount,
    required this.onShareRegia,
    required this.onInterrupt,
    required this.onCloseStream,
    required this.pointsTarget,
  });

  final Duration elapsed;
  final int batteryLevel;
  final String homeName;
  final String awayName;
  final ScoreState score;
  final String networkType;
  final double bitrateMbps;
  final int fps;
  final int viewerCount;
  final VoidCallback onShareRegia;
  final VoidCallback onInterrupt;
  final Future<void> Function() onCloseStream;
  final int pointsTarget;

  @override
  Widget build(BuildContext context) {
    final inset = ScreenInsets.cameraOverlay(context);

    return Column(
      children: [
        Padding(
          padding: EdgeInsets.fromLTRB(inset.left, inset.top, inset.right, 6),
          child: Row(
            children: [
              LiveBadge(elapsed: elapsed),
              const Spacer(),
              IconButton(
                onPressed: onShareRegia,
                icon: const Icon(Icons.share),
                tooltip: 'Condividi link regia',
              ),
              CameraCompactMetrics(
                networkType: networkType,
                bitrateMbps: bitrateMbps,
                fps: fps,
                batteryLevel: batteryLevel,
                viewerCount: viewerCount > 0 ? viewerCount : null,
              ),
            ],
          ),
        ),
        const Expanded(child: SizedBox.expand()),
        Container(
          color: AppTheme.background,
          padding: EdgeInsets.fromLTRB(
            inset.left,
            12,
            inset.right,
            math.max(inset.bottom, 16),
          ),
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              CameraScoreControls(
                homeName: homeName,
                awayName: awayName,
                homePoints: score.homePoints,
                awayPoints: score.awayPoints,
                currentSet: score.currentSet,
                homeSets: score.homeSets,
                awaySets: score.awaySets,
                pointsTarget: pointsTarget,
              ),
              const SizedBox(height: 10),
              OutlinedButton.icon(
                onPressed: onShareRegia,
                icon: const Icon(Icons.share, size: 18),
                label: const Text('Condividi link regia'),
              ),
              const SizedBox(height: 8),
              OutlinedButton(
                onPressed: onInterrupt,
                child: const Text('Interrompi (riprendibile)'),
              ),
              const SizedBox(height: 8),
              DestructiveCta(
                label: 'Chiudi diretta',
                onPressed: () => onCloseStream(),
              ),
            ],
          ),
        ),
      ],
    );
  }
}

class _LandscapeOverlay extends StatelessWidget {
  const _LandscapeOverlay({
    required this.elapsed,
    required this.batteryLevel,
    required this.homeName,
    required this.awayName,
    required this.score,
    required this.lastDelta,
    required this.networkType,
    required this.bitrateMbps,
    required this.fps,
    required this.viewerCount,
    required this.onShareRegia,
    required this.onInterrupt,
    required this.onCloseStream,
    required this.pointsTarget,
  });

  final Duration elapsed;
  final int batteryLevel;
  final String homeName;
  final String awayName;
  final ScoreState score;
  final int? lastDelta;
  final String networkType;
  final double bitrateMbps;
  final int fps;
  final int viewerCount;
  final VoidCallback onShareRegia;
  final VoidCallback onInterrupt;
  final Future<void> Function() onCloseStream;
  final int pointsTarget;

  @override
  Widget build(BuildContext context) {
    final inset = ScreenInsets.cameraOverlay(context);

    return Column(
      children: [
        Padding(
          padding: EdgeInsets.fromLTRB(inset.left, inset.top, inset.right, 6),
          child: Row(
            children: [
              LiveBadge(elapsed: elapsed, compact: true),
              const Spacer(),
              CameraCompactMetrics(
                networkType: networkType,
                bitrateMbps: bitrateMbps,
                fps: fps,
                batteryLevel: batteryLevel,
                viewerCount: viewerCount > 0 ? viewerCount : null,
                light: true,
              ),
            ],
          ),
        ),
        const Expanded(child: SizedBox.expand()),
        Container(
          color: Colors.black.withValues(alpha: 0.82),
          padding: EdgeInsets.fromLTRB(
            inset.left,
            10,
            inset.right,
            math.max(inset.bottom, 12),
          ),
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              CameraScoreControls(
                compact: true,
                homeName: homeName,
                awayName: awayName,
                homePoints: score.homePoints,
                awayPoints: score.awayPoints,
                currentSet: score.currentSet,
                homeSets: score.homeSets,
                awaySets: score.awaySets,
                lastDelta: lastDelta,
                pointsTarget: pointsTarget,
              ),
              const SizedBox(height: 8),
              Row(
                children: [
                  IconButton(
                    onPressed: onShareRegia,
                    icon: const Icon(Icons.share, color: Colors.white),
                    tooltip: 'Condividi link regia',
                  ),
                  Expanded(
                    child: OutlinedButton(
                      onPressed: onInterrupt,
                      child: const Text('Interrompi', style: TextStyle(fontSize: 11)),
                    ),
                  ),
                  const SizedBox(width: 8),
                  Expanded(
                    child: DestructiveCta(
                      label: 'Chiudi',
                      compact: true,
                      onPressed: () => onCloseStream(),
                    ),
                  ),
                ],
              ),
            ],
          ),
        ),
      ],
    );
  }
}
