import 'dart:async';

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 '../../app/theme.dart';
import '../../providers/match_rules_provider.dart';
import '../../providers/score_provider.dart';
import '../../providers/session_provider.dart';
import '../shared/live_score_actions.dart';
import '../../shared/widgets/end_stream_dialog.dart';
import '../../shared/api_client.dart';
import '../../shared/websocket_service.dart';
import '../../shared/widgets/connected_badge.dart';
import '../../shared/widgets/match_live_wordmark.dart';
import '../../shared/widgets/screen_insets.dart';
import 'controller_landscape.dart';
import 'controller_portrait.dart';

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

  final String sessionId;

  @override
  ConsumerState<ControllerScreen> createState() => _ControllerScreenState();
}

class _ControllerScreenState extends ConsumerState<ControllerScreen> {
  Timer? _elapsedTimer;
  Timer? _statsTimer;

  @override
  void initState() {
    super.initState();
    _lockLandscape();
    _bootstrap();
    _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!),
            );
      }
    });
    _statsTimer = Timer.periodic(const Duration(seconds: 30), (_) => _fetchStats());
  }

  Future<void> _bootstrap() async {
    try {
      final client = ref.read(apiClientProvider);
      final session = await client.fetchSession(widget.sessionId);
      ref.read(sessionProvider.notifier).setSession(session);
      if (session.score != null) {
        ref.read(scoreProvider.notifier).reset(session.score!);
      }
      final ws = ref.read(websocketServiceProvider);
      await ws.connect(sessionId: widget.sessionId, deviceRole: 'controller');
    } catch (_) {
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          const SnackBar(content: Text('Errore connessione sessione')),
        );
      }
    }
  }

  Future<void> _fetchStats() async {
    try {
      final client = ref.read(apiClientProvider);
      final stats = await client.youtubeStats(widget.sessionId);
      ref.read(sessionProvider.notifier).setViewerCount(stats.concurrentViewers);
    } catch (_) {}
  }

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

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

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

  Future<void> _interruptStream() async {
    try {
      ref.read(websocketServiceProvider).sendCommand('pause_stream');
      await ref.read(apiClientProvider).pauseSession(widget.sessionId);
    } catch (e) {
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('Pausa: $e')),
        );
      }
    }
    await _leaveSession();
  }

  Future<void> _closeStreamPermanently() async {
    if (!mounted) return;
    final ok = await confirmEndStream(context);
    if (!ok || !mounted) return;

    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: $e')),
        );
      }
    }
    await _leaveSession();
  }

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

  void _syncScore() {
    ref.read(websocketServiceProvider).sendScoreUpdate(ref.read(scoreProvider));
  }

  Future<void> _homePoint() async {
    ref.read(scoreProvider.notifier).incrementHome();
    _syncScore();
    final match = ref.read(sessionProvider).match;
    await LiveScoreActions(ref).afterPointChange(
      context,
      homeName: match?.teamName ?? 'Casa',
      awayName: match?.opponentName ?? 'Ospiti',
      onCloseSetConfirmed: () => _closeSetConfirmed(),
    );
  }

  Future<void> _awayPoint() async {
    ref.read(scoreProvider.notifier).incrementAway();
    _syncScore();
    final match = ref.read(sessionProvider).match;
    await LiveScoreActions(ref).afterPointChange(
      context,
      homeName: match?.teamName ?? 'Casa',
      awayName: match?.opponentName ?? 'Ospiti',
      onCloseSetConfirmed: () => _closeSetConfirmed(),
    );
  }

  void _homeMinus() {
    ref.read(scoreProvider.notifier).decrementHome();
    _syncScore();
  }

  void _awayMinus() {
    ref.read(scoreProvider.notifier).decrementAway();
    _syncScore();
  }

  Future<void> _closeSet() async {
    await LiveScoreActions(ref).requestCloseSet(
      context,
      onCloseSetConfirmed: () => _closeSetConfirmed(),
    );
  }

  Future<void> _closeSetConfirmed() async {
    ref.read(scoreProvider.notifier).closeSet();
    _syncScore();
    final match = ref.read(sessionProvider).match;
    await LiveScoreActions(ref).afterCloseSet(
      context,
      homeName: match?.teamName ?? 'Casa',
      awayName: match?.opponentName ?? 'Ospiti',
      onStopStream: _closeStreamPermanently,
    );
  }

  @override
  Widget build(BuildContext context) {
    final sessionState = ref.watch(sessionProvider);
    final score = ref.watch(scoreProvider);
    final match = sessionState.match;
    final isLandscape =
        MediaQuery.orientationOf(context) == Orientation.landscape;

    final homeName = match?.teamName ?? 'CASA';
    final awayName = match?.opponentName ?? 'OSPITI';
    final rules = ref.watch(matchScoringRulesProvider);
    final pointsTarget = rules.pointsTarget(score.currentSet);

    final body = isLandscape
        ? ControllerLandscape(
            homeName: homeName,
            awayName: awayName,
            score: score,
            sessionState: sessionState,
            pointsTarget: pointsTarget,
            onHomePoint: () => _homePoint(),
            onAwayPoint: () => _awayPoint(),
            onHomeMinus: _homeMinus,
            onAwayMinus: _awayMinus,
            onCloseSet: () => _closeSet(),
            onInterrupt: _interruptStream,
            onCloseStream: _closeStreamPermanently,
          )
        : ControllerPortrait(
            homeName: homeName,
            awayName: awayName,
            score: score,
            sessionState: sessionState,
            pointsTarget: pointsTarget,
            onHomePoint: () => _homePoint(),
            onAwayPoint: () => _awayPoint(),
            onHomeMinus: _homeMinus,
            onAwayMinus: _awayMinus,
            onCloseSet: () => _closeSet(),
            onInterrupt: _interruptStream,
            onCloseStream: _closeStreamPermanently,
          );

    final inset = ScreenInsets.of(context);

    return Scaffold(
      backgroundColor: AppTheme.background,
      body: Column(
        children: [
          if (!isLandscape)
            Padding(
              padding: EdgeInsets.fromLTRB(
                inset.left,
                inset.top,
                inset.right,
                8,
              ),
              child: Row(
                children: [
                  const MatchLiveWordmark(compact: true),
                  const Spacer(),
                  ConnectedBadge(connected: sessionState.connected),
                ],
              ),
            ),
          Expanded(
            child: Padding(
              padding: EdgeInsets.only(
                left: inset.left,
                right: inset.right,
                top: isLandscape ? inset.top : 0,
                bottom: inset.bottom,
              ),
              child: body,
            ),
          ),
        ],
      ),
    );
  }
}

/// Pulsante score +1 con stile gamepad.
class ScoreTapButton extends StatelessWidget {
  const ScoreTapButton({
    super.key,
    required this.label,
    required this.onTap,
    this.large = false,
  });

  final String label;
  final VoidCallback onTap;
  final bool large;

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    return Material(
      color: AppTheme.surfaceElevated,
      borderRadius: BorderRadius.circular(large ? 16 : 12),
      child: InkWell(
        onTap: onTap,
        borderRadius: BorderRadius.circular(large ? 16 : 12),
        child: Container(
          width: large ? double.infinity : null,
          padding: EdgeInsets.symmetric(
            vertical: large ? 20 : 12,
            horizontal: large ? 24 : 16,
          ),
          child: Text(
            label,
            textAlign: TextAlign.center,
            style: theme.textTheme.headlineSmall?.copyWith(
              fontWeight: FontWeight.w900,
              fontSize: large ? 28 : 18,
            ),
          ),
        ),
      ),
    );
  }
}

/// CTA gialla per azioni secondarie (PAUSA, CHIUDI SET).
class YellowActionButton extends StatelessWidget {
  const YellowActionButton({
    super.key,
    required this.label,
    required this.onPressed,
  });

  final String label;
  final VoidCallback onPressed;

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    return SizedBox(
      width: double.infinity,
      child: ElevatedButton(
        onPressed: onPressed,
        style: ElevatedButton.styleFrom(
          backgroundColor: AppTheme.accentYellow,
          foregroundColor: Colors.black,
          padding: const EdgeInsets.symmetric(vertical: 14),
          shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
        ),
        child: Text(
          label,
          style: theme.textTheme.labelLarge?.copyWith(color: Colors.black),
        ),
      ),
    );
  }
}

/// Footer metriche stream (timer, segnale, Mbps, batteria).
class StreamMetricsFooter extends StatelessWidget {
  const StreamMetricsFooter({
    super.key,
    required this.elapsed,
    required this.connected,
    this.cameraDevice,
    this.viewerCount,
    this.compact = false,
  });

  final Duration elapsed;
  final bool connected;
  final dynamic cameraDevice;
  final int? viewerCount;
  final bool compact;

  String _format(Duration d) {
    final m = d.inMinutes.remainder(60).toString().padLeft(2, '0');
    final s = d.inSeconds.remainder(60).toString().padLeft(2, '0');
    return '$m:$s';
  }

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    final network = cameraDevice?.networkType ?? '—';
    final mbps = cameraDevice?.bitrateMbps != null
        ? cameraDevice.bitrateMbps.toStringAsFixed(1)
        : '—';
    final battery = cameraDevice?.batteryLevel?.toString() ?? '—';

    return Container(
      padding: EdgeInsets.all(compact ? 8 : 12),
      decoration: BoxDecoration(
        color: AppTheme.surface,
        borderRadius: BorderRadius.circular(compact ? 8 : 10),
      ),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: [
          _MetricChip(icon: Icons.timer, label: _format(elapsed)),
          _MetricChip(icon: Icons.signal_cellular_alt, label: network),
          _MetricChip(icon: Icons.speed, label: '$mbps Mbps'),
          _MetricChip(icon: Icons.battery_std, label: '$battery%'),
          if (viewerCount != null)
            _MetricChip(icon: Icons.visibility, label: '$viewerCount'),
          ConnectedBadge(connected: connected, label: compact ? null : 'COLLEGATO'),
        ],
      ),
    );
  }
}

class _MetricChip extends StatelessWidget {
  const _MetricChip({required this.icon, required this.label});

  final IconData icon;
  final String label;

  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisSize: MainAxisSize.min,
      children: [
        Icon(icon, size: 14, color: AppTheme.textSecondary),
        const SizedBox(width: 4),
        Text(label, style: Theme.of(context).textTheme.labelLarge?.copyWith(fontSize: 11)),
      ],
    );
  }
}
