import 'dart:ui';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:video_player/video_player.dart';
import 'package:youtube_player_flutter/youtube_player_flutter.dart';

import '../watched_videos_prefs.dart';
import '../widgets/app_gradients.dart';
import '../widgets/entrance.dart';
import '../widgets/liquid_waves_background.dart';
import '../widgets/pill_snackbar.dart';
import '../widgets/tap_bounce.dart';

// Video data structure - easily editable for future updates.
// Episódios 1-10 tocam via YouTube (não listado). Episódios 11-13 ainda não
// foram subidos ao YouTube e continuam embutidos no app (assets/videos) até
// lá — depois de subidos, troque videoPath por youtubeId e apague o mp4.
class VideoData {
  final int id;
  final String title;
  final String description;
  final String? videoPath;
  final String? youtubeId;

  VideoData({
    required this.id,
    required this.title,
    required this.description,
    this.videoPath,
    this.youtubeId,
  });
}

// List of all videos - edit titles and descriptions here
final List<VideoData> videoList = [
  VideoData(
    id: 1,
    title: 'Episódio 1',
    description: 'Qual a Influência do nariz entupido na má oclusão',
    youtubeId: 'PJ58CZv4ECw',
  ),
  VideoData(
    id: 2,
    title: 'Episódio 2',
    description: 'Qual a Influência das alergias sazionais na má oclusão',
    youtubeId: 'y4_kWmZtAtg',
  ),
  VideoData(
    id: 3,
    title: 'Episódio 3',
    description: 'Qual a Influência das Otites frequentes na má oclusão',
    youtubeId: 'nD75Y5PuKTo',
  ),
  VideoData(
    id: 4,
    title: 'Episódio 4',
    description: 'Qual a Influência das Amigdalites recorrentes na má oclusão',
    youtubeId: 'yvFllWYeuLw',
  ),
  VideoData(
    id: 5,
    title: 'Episódio 5',
    description:
        'Qual a Influência das Bronquiolites recorrentes na má oclusão',
    youtubeId: 'DnhUa-T8_Ps',
  ),
  VideoData(
    id: 6,
    title: 'Episódio 6',
    description: 'Qual a Influência dos problemas respitatórios na má oclusão',
    youtubeId: 'zKt_iwkrjvo',
  ),
  VideoData(
    id: 7,
    title: 'Episódio 7',
    description:
        'Qual a Influência das interrupções respiratórias na má oclusão',
    youtubeId: 'NpmQ2brap5A',
  ),
  VideoData(
    id: 8,
    title: 'Episódio 8',
    description: 'Qual a Influência do ressonar na má oclusão',
    youtubeId: 'Wj3KYw9pBi0',
  ),
  VideoData(
    id: 9,
    title: 'Episódio 9',
    description:
        'Qual a Influência de acordar com saliva seca na boca ou na almofada na saúde oral',
    youtubeId: 'bOm9t61cT_U',
  ),
  VideoData(
    id: 10,
    title: 'Episódio 10',
    description: 'Qual a Influência da respiração oral na má oclusão',
    youtubeId: 'fAitMizbcms',
  ),
  VideoData(
    id: 11,
    title: 'Episódio 11',
    description: 'Qual a influência do uso exagerado da chupeta na má oclusão',
    youtubeId: '6sYoBUjks_I',
  ),
  VideoData(
    id: 12,
    title: 'Episódio 12',
    description: 'Qual a influência do uso exagerado da chupeta na má oclusão',
    youtubeId: 'eznKrErQbHo',
  ),
  VideoData(
    id: 13,
    title: 'Episódio 13',
    description: 'Qual a influência do hábito de chuchar o dedo na má oclusão',
    youtubeId: 'VO9CNqHRdeM',
  ),
];

// Cache de controllers de vídeo, partilhado entre qualquer ecrã que mostre
// uma prévia (grelha de vídeos e o cartão em destaque na Home). Como vários
// widgets podem apontar para o mesmo controller ao mesmo tempo, mantemos uma
// contagem de referências para só o libertar quando ninguém mais o usa.
final Map<String, VideoPlayerController> _videoControllerCache = {};
final Map<String, int> _videoControllerRefCounts = {};

// Dispositivos (sobretudo emuladores) só suportam um número pequeno de
// decodificadores de vídeo/áudio simultâneos. A grelha de vídeos pode ter
// dezenas de prévias e o GridView constrói várias de uma vez ao rolar; sem
// este limite, cada thumbnail tenta abrir o seu próprio decoder e o sistema
// trava (era exatamente isto que causava o congelamento e perda de som ao
// navegar por muitos vídeos). Acima do limite, a prévia simplesmente mostra
// o ícone de play em vez do frame real do vídeo.
const int _maxConcurrentThumbnailDecoders = 1;

bool get _hasThumbnailDecoderSlot =>
    _videoControllerCache.length < _maxConcurrentThumbnailDecoders;

void _releaseVideoController(String path) {
  final remaining = (_videoControllerRefCounts[path] ?? 0) - 1;
  if (remaining > 0) {
    _videoControllerRefCounts[path] = remaining;
    return;
  }
  _videoControllerRefCounts.remove(path);
  _videoControllerCache.remove(path)?.dispose();
}

/// Descarta TODOS os controllers de prévia em cache. Chamado antes de abrir
/// um player real (dialog/fullscreen), que já precisa dos seus próprios
/// decodificadores de vídeo e áudio — em dispositivos com pouca capacidade
/// (sobretudo emuladores), manter qualquer prévia viva ao mesmo tempo é
/// suficiente para esgotar os decodificadores e travar o aparelho.
void _evictAllVideoControllers() {
  _videoControllerRefCounts.clear();
  final controllers = _videoControllerCache.values.toList();
  _videoControllerCache.clear();
  for (final controller in controllers) {
    controller.dispose();
  }
}

/// Regista o episódio como assistido (localmente, por criança). Chamado
/// quando um player deteta que o vídeo chegou ao fim — sem [scopeId] (nenhuma
/// criança selecionada) não há onde guardar, por isso não faz nada.
void markVideoWatched(String? scopeId, int videoId) {
  final scope = (scopeId ?? '').trim();
  if (scope.isEmpty) return;
  WatchedVideosPrefs.markWatched(scope, videoId);
}

Future<void> showVideoPlayerDialog(
  BuildContext context,
  VideoData video, {
  String? scopeId,
}) {
  if (video.youtubeId != null) {
    if (video.youtubeId!.isEmpty) {
      showPillSnackBar(context, 'Vídeo ainda não disponível');
      return Future.value();
    }
    return Navigator.of(context).push<void>(
      MaterialPageRoute(
        builder: (context) =>
            _YoutubePlayerPage(video: video, scopeId: scopeId),
      ),
    );
  }
  return showDialog<void>(
    context: context,
    builder: (context) => _VideoPlayerDialog(video: video, scopeId: scopeId),
  );
}

class VideoScreen extends StatefulWidget {
  const VideoScreen({super.key, this.scopeId});

  /// Identifica a criança selecionada (`'${uid}_${childId}'`), usado para
  /// guardar localmente quais episódios ela já assistiu até ao fim.
  final String? scopeId;

  static const Color _teal = Color(0xFF2F9E94);
  static const Color _accentPink = Color(0xFFFF55A7);

  @override
  State<VideoScreen> createState() => _VideoScreenState();
}

class _VideoScreenState extends State<VideoScreen> {
  final TextEditingController _searchController = TextEditingController();
  List<VideoData> _filteredVideos = videoList;

  @override
  void initState() {
    super.initState();
    _filteredVideos = videoList;
    _searchController.addListener(_onSearchChanged);
  }

  @override
  void dispose() {
    _searchController.dispose();
    // Não descartamos o cache global aqui: outros widgets (como o cartão em
    // destaque na Home) podem estar a usar os mesmos controllers. Cada
    // [VideoThumbnail] liberta a sua própria referência ao ser desmontado.
    super.dispose();
  }

  void _onSearchChanged() {
    final query = _searchController.text.toLowerCase();
    setState(() {
      _filteredVideos = videoList
          .where((video) => video.title.toLowerCase().contains(query))
          .toList();
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: PreferredSize(
        preferredSize: const Size.fromHeight(kToolbarHeight),
        // O gradiente é pintado por este Container de tamanho fixo, em vez
        // de confiar no `flexibleSpace` do AppBar — em alguns aparelhos o
        // `flexibleSpace` de um AppBar comum não recebia o tamanho esperado
        // e a gradiente aparecia como cor sólida.
        child: Container(
          decoration: const BoxDecoration(gradient: kAppBarGradient),
          child: AppBar(
            backgroundColor: Colors.transparent,
            foregroundColor: Colors.white,
            surfaceTintColor: Colors.transparent,
            elevation: 0,
            scrolledUnderElevation: 0,
            title: const Text(
              'Vídeos Educativos',
              style: TextStyle(fontWeight: FontWeight.w900),
            ),
          ),
        ),
      ),
      body: Stack(
        clipBehavior: Clip.none,
        children: [
          Positioned.fill(child: Container(color: const Color(0xFFFAFAF7))),
          const LiquidWavesBackground(),
          SafeArea(
            child: Padding(
              padding: const EdgeInsets.all(16),
              child: Column(
                children: [
                  // Search bar
                  Container(
                    decoration: BoxDecoration(
                      color: Colors.white.withValues(alpha: 0.9),
                      borderRadius: BorderRadius.circular(16),
                      boxShadow: [
                        BoxShadow(
                          color: Colors.black.withValues(alpha: 0.08),
                          blurRadius: 8,
                          offset: const Offset(0, 2),
                        ),
                      ],
                    ),
                    child: TextField(
                      controller: _searchController,
                      decoration: InputDecoration(
                        hintText: 'Pesquisar vídeos...',
                        prefixIcon: const Icon(
                          Icons.search,
                          color: VideoScreen._teal,
                        ),
                        border: InputBorder.none,
                        contentPadding: const EdgeInsets.symmetric(
                          horizontal: 16,
                          vertical: 14,
                        ),
                      ),
                    ),
                  ),
                  const SizedBox(height: 16),
                  // Lista vertical (um vídeo abaixo do outro, rolando para
                  // baixo), mas cada card em si é horizontal — miniatura à
                  // esquerda, título/descrição à direita — em vez da antiga
                  // grelha de 2 colunas com cards verticais.
                  Expanded(
                    child: _filteredVideos.isEmpty
                        ? Center(
                            child: Text(
                              'Nenhum vídeo encontrado',
                              style: TextStyle(
                                fontSize: 16,
                                fontWeight: FontWeight.w600,
                                color: Colors.black.withValues(alpha: 0.6),
                              ),
                            ),
                          )
                        : ListView.separated(
                            itemCount: _filteredVideos.length,
                            separatorBuilder: (context, index) =>
                                const SizedBox(height: 12),
                            itemBuilder: (context, index) {
                              return FadeSlideIn(
                                delay: Duration(milliseconds: 40 * (index % 8)),
                                child: _VideoButton(
                                  video: _filteredVideos[index],
                                  scopeId: widget.scopeId,
                                ),
                              );
                            },
                          ),
                  ),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }
}

/// Preview de um vídeo (frame local ou thumbnail do YouTube), reutilizável
/// em qualquer card que precise mostrar "a cara" de um episódio.
class VideoThumbnail extends StatefulWidget {
  const VideoThumbnail({
    super.key,
    required this.video,
    this.borderRadius = 12,
    this.iconSize = 48,
  });

  final VideoData video;
  final double borderRadius;
  final double iconSize;

  @override
  State<VideoThumbnail> createState() => _VideoThumbnailState();
}

class _VideoThumbnailState extends State<VideoThumbnail> {
  VideoPlayerController? _controller;
  bool _isInitialized = false;
  bool _hasOwnRef = false;

  bool get _isYoutube => widget.video.youtubeId != null;

  /// Verdadeiro quando outro widget descartou o controller que este
  /// thumbnail estava a usar (ex.: ao abrir o player em dialog/fullscreen).
  /// Nesse caso [_controller] deixou de ser o mesmo objeto guardado no
  /// cache partilhado — nunca é seguro tocar num controller já disposed.
  bool get _isControllerStale =>
      _controller != null &&
      _videoControllerCache[widget.video.videoPath] != _controller;

  @override
  void initState() {
    super.initState();
    if (!_isYoutube) _initializeVideo();
  }

  Future<void> _initializeVideo() async {
    final path = widget.video.videoPath!;
    final cached = _videoControllerCache[path];
    if (cached != null) {
      _controller = cached;
      _videoControllerRefCounts[path] =
          (_videoControllerRefCounts[path] ?? 0) + 1;
      _hasOwnRef = true;
      try {
        await cached.seekTo(const Duration(seconds: 2));
        await cached.pause();
        if (mounted) setState(() => _isInitialized = true);
      } catch (_) {
        // O controller partilhado foi descartado por outra tela entretanto;
        // larga a referência inválida e cria um novo do zero.
        _releaseOwnRef();
        _controller = null;
        if (mounted) await _createFreshController(path);
      }
      return;
    }
    if (!_hasThumbnailDecoderSlot) {
      // Já há decoders suficientes ativos noutras prévias; fica só com o
      // ícone de play em vez de arriscar sobrecarregar o dispositivo.
      if (mounted) setState(() => _isInitialized = false);
      return;
    }
    await _createFreshController(path);
  }

  Future<void> _createFreshController(String path) async {
    final controller = VideoPlayerController.asset(path);
    _controller = controller;
    try {
      await controller.initialize();
      await controller.seekTo(const Duration(seconds: 2));
      await controller.pause();
      _videoControllerCache[path] = controller;
      _videoControllerRefCounts[path] =
          (_videoControllerRefCounts[path] ?? 0) + 1;
      _hasOwnRef = true;
      if (mounted) setState(() => _isInitialized = true);
    } catch (e) {
      if (mounted) setState(() => _isInitialized = false);
    }
  }

  void _releaseOwnRef() {
    final path = widget.video.videoPath;
    if (_hasOwnRef && path != null) {
      _releaseVideoController(path);
      _hasOwnRef = false;
    }
  }

  @override
  void dispose() {
    _releaseOwnRef();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    if (_isYoutube) {
      final youtubeId = widget.video.youtubeId!;
      if (youtubeId.isEmpty) {
        return Center(
          child: Icon(
            Icons.hourglass_top_rounded,
            size: widget.iconSize * 0.85,
            color: Colors.black26,
          ),
        );
      }
      return ClipRRect(
        borderRadius: BorderRadius.circular(widget.borderRadius),
        child: Image.network(
          'https://img.youtube.com/vi/$youtubeId/hqdefault.jpg',
          fit: BoxFit.cover,
          width: double.infinity,
          height: double.infinity,
          errorBuilder: (context, error, stackTrace) => Center(
            child: Icon(
              Icons.play_circle_fill_rounded,
              size: widget.iconSize,
              color: VideoScreen._accentPink,
            ),
          ),
        ),
      );
    }

    if (_isControllerStale) {
      // Não mexemos no controller antigo (pode já estar disposed); larga a
      // referência e agenda uma reinicialização para o próximo frame.
      _hasOwnRef = false;
      _controller = null;
      _isInitialized = false;
      WidgetsBinding.instance.addPostFrameCallback((_) {
        if (mounted) _initializeVideo();
      });
    }

    return _isInitialized && _controller != null
        ? ClipRRect(
            borderRadius: BorderRadius.circular(widget.borderRadius),
            child: FittedBox(
              fit: BoxFit.cover,
              child: SizedBox(
                width: _controller!.value.size.width,
                height: _controller!.value.size.height,
                child: VideoPlayer(_controller!),
              ),
            ),
          )
        : Center(
            child: Icon(
              Icons.play_circle_fill_rounded,
              size: widget.iconSize,
              color: VideoScreen._accentPink,
            ),
          );
  }
}

class _VideoButton extends StatelessWidget {
  const _VideoButton({required this.video, this.scopeId});

  final VideoData video;
  final String? scopeId;

  void _showVideoPlayer(BuildContext context, VideoData video) {
    if (video.youtubeId == null) {
      // Liberta todos os decodificadores de prévia antes de abrir o player
      // em dialog, que precisa dos seus próprios decoders de vídeo/áudio.
      _evictAllVideoControllers();
    }
    showVideoPlayerDialog(context, video, scopeId: scopeId);
  }

  @override
  Widget build(BuildContext context) {
    return TapBounce(
      scale: 0.97,
      child: Material(
        elevation: 8,
        shadowColor: Colors.black.withValues(alpha: 0.14),
        borderRadius: BorderRadius.circular(18),
        color: Colors.white,
        child: InkWell(
          borderRadius: BorderRadius.circular(18),
          onTap: () => _showVideoPlayer(context, video),
          child: Padding(
            padding: const EdgeInsets.all(10),
            child: Row(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                SizedBox(
                  width: 130,
                  child: AspectRatio(
                    aspectRatio: 16 / 9,
                    child: ClipRRect(
                      borderRadius: BorderRadius.circular(14),
                      child: Stack(
                        fit: StackFit.expand,
                        children: [
                          ColoredBox(
                            color: const Color(0xFFFFE6F1),
                            child: VideoThumbnail(
                              video: video,
                              borderRadius: 0,
                            ),
                          ),
                          DecoratedBox(
                            decoration: BoxDecoration(
                              gradient: LinearGradient(
                                begin: Alignment.topCenter,
                                end: Alignment.bottomCenter,
                                colors: [
                                  Colors.transparent,
                                  Colors.black.withValues(alpha: 0.32),
                                ],
                                stops: const [0.55, 1.0],
                              ),
                            ),
                          ),
                          Center(
                            child: Container(
                              width: 34,
                              height: 34,
                              decoration: BoxDecoration(
                                color: Colors.white.withValues(alpha: 0.92),
                                shape: BoxShape.circle,
                              ),
                              child: const Icon(
                                Icons.play_arrow_rounded,
                                color: VideoScreen._accentPink,
                                size: 20,
                              ),
                            ),
                          ),
                          Positioned(
                            left: 6,
                            bottom: 6,
                            child: Container(
                              padding: const EdgeInsets.symmetric(
                                horizontal: 6,
                                vertical: 2,
                              ),
                              decoration: BoxDecoration(
                                color: Colors.black.withValues(alpha: 0.5),
                                borderRadius: BorderRadius.circular(999),
                              ),
                              child: Text(
                                'EP. ${video.id}',
                                style: const TextStyle(
                                  color: Colors.white,
                                  fontWeight: FontWeight.w800,
                                  fontSize: 9.5,
                                ),
                              ),
                            ),
                          ),
                        ],
                      ),
                    ),
                  ),
                ),
                const SizedBox(width: 12),
                Expanded(
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text(
                        video.title,
                        style: const TextStyle(
                          fontWeight: FontWeight.w900,
                          fontSize: 15,
                          color: VideoScreen._teal,
                        ),
                        maxLines: 1,
                        overflow: TextOverflow.ellipsis,
                      ),
                      const SizedBox(height: 4),
                      Text(
                        video.description,
                        style: TextStyle(
                          fontSize: 12,
                          fontWeight: FontWeight.w600,
                          color: Colors.black.withValues(alpha: 0.6),
                        ),
                        maxLines: 2,
                        overflow: TextOverflow.ellipsis,
                      ),
                    ],
                  ),
                ),
                const SizedBox(width: 4),
                Icon(
                  Icons.chevron_right_rounded,
                  color: Colors.black.withValues(alpha: 0.3),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

/// Página cheia (não diálogo) para o player do YouTube. O botão de tela cheia
/// do próprio player força a rotação para paisagem via
/// `SystemChrome.setPreferredOrientations`; um `Dialog` de largura fixa não
/// se adapta a essa rotação e causa overflow gráfico.
///
/// Em paisagem/tela cheia, o vídeo é recortado ("cover", como Instagram/
/// TikTok) para preencher o ecrã todo sem barras pretas — em vez de manter
/// a proporção 16:9 do YouTube e sobrar espaço vazio quando o ecrã tem uma
/// proporção mais larga que 16:9 (ex.: a maioria dos telemóveis atuais).
class _YoutubePlayerPage extends StatefulWidget {
  const _YoutubePlayerPage({required this.video, this.scopeId});

  final VideoData video;
  final String? scopeId;

  @override
  State<_YoutubePlayerPage> createState() => _YoutubePlayerPageState();
}

class _YoutubePlayerPageState extends State<_YoutubePlayerPage>
    with WidgetsBindingObserver {
  late final YoutubePlayerController _controller;
  bool _markedWatched = false;

  @override
  void initState() {
    super.initState();
    _controller = YoutubePlayerController(
      initialVideoId: widget.video.youtubeId!,
      flags: const YoutubePlayerFlags(autoPlay: true, mute: false),
    );
    _controller.addListener(_onControllerValueChanged);
    WidgetsBinding.instance.addObserver(this);
  }

  void _onControllerValueChanged() {
    if (_markedWatched) return;
    if (_controller.value.playerState == PlayerState.ended) {
      _markedWatched = true;
      markVideoWatched(widget.scopeId, widget.video.id);
    }
  }

  @override
  void didChangeMetrics() {
    final isLandscape =
        PlatformDispatcher.instance.views.first.physicalSize.width >
        PlatformDispatcher.instance.views.first.physicalSize.height;
    if (isLandscape == _controller.value.isFullScreen) return;
    _controller.updateValue(
      _controller.value.copyWith(isFullScreen: isLandscape),
    );
    if (isLandscape) {
      SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky);
    } else {
      SystemChrome.restoreSystemUIOverlays();
    }
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    SystemChrome.restoreSystemUIOverlays();
    _controller.removeListener(_onControllerValueChanged);
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return ValueListenableBuilder<YoutubePlayerValue>(
      valueListenable: _controller,
      builder: (context, value, _) {
        return PopScope(
          canPop: !value.isFullScreen,
          onPopInvokedWithResult: (didPop, _) {
            if (!didPop) _controller.toggleFullScreenMode();
          },
          child: Scaffold(
            backgroundColor: value.isFullScreen
                ? Colors.black
                : const Color(0xFFFAFAF7),
            appBar: value.isFullScreen
                ? null
                : PreferredSize(
                    preferredSize: const Size.fromHeight(kToolbarHeight),
                    child: Container(
                      decoration: const BoxDecoration(
                        gradient: kAppBarGradient,
                      ),
                      child: AppBar(
                        backgroundColor: Colors.transparent,
                        foregroundColor: Colors.white,
                        surfaceTintColor: Colors.transparent,
                        elevation: 0,
                        scrolledUnderElevation: 0,
                        title: Text(
                          widget.video.title,
                          style: const TextStyle(fontWeight: FontWeight.w900),
                        ),
                      ),
                    ),
                  ),
            // Em vez de centrar o vídeo num quadro 16:9 no meio de um ecrã
            // preto (o que sobrava como barras pretas em cima/baixo no
            // modo retrato), o vídeo fica encostado ao topo, a preencher a
            // largura toda, com o título e a descrição do episódio logo
            // abaixo — sem nenhum espaço preto sobrando. O modo tela cheia
            // (paisagem) continua a recortar o vídeo para preencher tudo.
            body: value.isFullScreen
                ? _CoverYoutubePlayer(controller: _controller)
                : SingleChildScrollView(
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        DecoratedBox(
                          decoration: const BoxDecoration(
                            gradient: kAppBarGradient,
                          ),
                          child: AspectRatio(
                            aspectRatio: 16 / 9,
                            child: YoutubePlayer(controller: _controller),
                          ),
                        ),
                        Padding(
                          padding: const EdgeInsets.fromLTRB(20, 14, 20, 0),
                          child: _VideoProgressRow(controller: _controller),
                        ),
                        Padding(
                          padding: const EdgeInsets.fromLTRB(20, 16, 20, 20),
                          child: Column(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                              Text(
                                widget.video.title,
                                style: const TextStyle(
                                  fontWeight: FontWeight.w900,
                                  fontSize: 19,
                                  color: VideoScreen._teal,
                                ),
                              ),
                              const SizedBox(height: 8),
                              Text(
                                widget.video.description,
                                style: TextStyle(
                                  fontSize: 14,
                                  fontWeight: FontWeight.w600,
                                  color: Colors.black.withValues(alpha: 0.65),
                                  height: 1.4,
                                ),
                              ),
                              if (_nextVideos.isNotEmpty) ...[
                                const SizedBox(height: 24),
                                Row(
                                  mainAxisAlignment:
                                      MainAxisAlignment.spaceBetween,
                                  children: [
                                    const Text(
                                      'Próximos',
                                      style: TextStyle(
                                        fontWeight: FontWeight.w900,
                                        fontSize: 15,
                                        color: VideoScreen._accentPink,
                                      ),
                                    ),
                                    if (_hasMoreVideos)
                                      TapBounce(
                                        child: InkWell(
                                          borderRadius: BorderRadius.circular(
                                            999,
                                          ),
                                          onTap: () =>
                                              Navigator.of(context).push(
                                                MaterialPageRoute<void>(
                                                  builder: (_) => VideoScreen(
                                                    scopeId: widget.scopeId,
                                                  ),
                                                ),
                                              ),
                                          child: const Padding(
                                            padding: EdgeInsets.symmetric(
                                              horizontal: 4,
                                              vertical: 2,
                                            ),
                                            child: Text(
                                              'Ver mais',
                                              style: TextStyle(
                                                fontWeight: FontWeight.w800,
                                                fontSize: 13,
                                                color: VideoScreen._teal,
                                              ),
                                            ),
                                          ),
                                        ),
                                      ),
                                  ],
                                ),
                                const SizedBox(height: 12),
                                for (
                                  var i = 0;
                                  i < _visibleNextVideos.length;
                                  i++
                                ) ...[
                                  if (i > 0) const SizedBox(height: 10),
                                  _VideoButton(
                                    video: _visibleNextVideos[i],
                                    scopeId: widget.scopeId,
                                  ),
                                ],
                              ],
                            ],
                          ),
                        ),
                      ],
                    ),
                  ),
          ),
        );
      },
    );
  }

  static const int _maxNextVideos = 4;

  List<VideoData> get _nextVideos =>
      videoList.where((v) => v.id > widget.video.id).toList();

  List<VideoData> get _visibleNextVideos =>
      _nextVideos.take(_maxNextVideos).toList();

  bool get _hasMoreVideos => _nextVideos.length > _maxNextVideos;
}

/// Barra de progresso do vídeo (posição atual / duração total), separada do
/// player — a mesma que aparece por baixo do vídeo no design de referência.
class _VideoProgressRow extends StatelessWidget {
  const _VideoProgressRow({required this.controller});

  final YoutubePlayerController controller;

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

  @override
  Widget build(BuildContext context) {
    return ValueListenableBuilder<YoutubePlayerValue>(
      valueListenable: controller,
      builder: (context, value, _) {
        final duration = value.metaData.duration;
        final position = value.position;
        final progress = duration.inMilliseconds > 0
            ? (position.inMilliseconds / duration.inMilliseconds).clamp(
                0.0,
                1.0,
              )
            : 0.0;
        return Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            ClipRRect(
              borderRadius: BorderRadius.circular(999),
              child: LinearProgressIndicator(
                value: progress,
                minHeight: 5,
                backgroundColor: Colors.black.withValues(alpha: 0.10),
                valueColor: const AlwaysStoppedAnimation(
                  VideoScreen._accentPink,
                ),
              ),
            ),
            const SizedBox(height: 6),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                Text(
                  _format(position),
                  style: TextStyle(
                    fontSize: 12,
                    fontWeight: FontWeight.w700,
                    color: Colors.black.withValues(alpha: 0.55),
                  ),
                ),
                Text(
                  _format(duration),
                  style: TextStyle(
                    fontSize: 12,
                    fontWeight: FontWeight.w700,
                    color: Colors.black.withValues(alpha: 0.55),
                  ),
                ),
              ],
            ),
          ],
        );
      },
    );
  }
}

/// Preenche todo o espaço disponível recortando o vídeo (mantém a proporção
/// 16:9 real do YouTube, mas amplia e corta o excesso nas laterais ou em
/// cima/baixo em vez de deixar barras pretas). O player é sempre desenhado
/// no seu tamanho real (nunca reduzido a uma caixa minúscula), por isso o
/// recorte fica nítido, sem perda de qualidade.
class _CoverYoutubePlayer extends StatelessWidget {
  const _CoverYoutubePlayer({required this.controller});

  final YoutubePlayerController controller;

  static const double _videoAspectRatio = 16 / 9;

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraints) {
        final parentAspectRatio = constraints.maxWidth / constraints.maxHeight;
        final double boxWidth;
        final double boxHeight;
        if (parentAspectRatio > _videoAspectRatio) {
          boxWidth = constraints.maxWidth;
          boxHeight = boxWidth / _videoAspectRatio;
        } else {
          boxHeight = constraints.maxHeight;
          boxWidth = boxHeight * _videoAspectRatio;
        }
        return ClipRect(
          child: OverflowBox(
            maxWidth: boxWidth,
            maxHeight: boxHeight,
            child: SizedBox(
              width: boxWidth,
              height: boxHeight,
              child: YoutubePlayer(
                controller: controller,
                aspectRatio: _videoAspectRatio,
              ),
            ),
          ),
        );
      },
    );
  }
}

class _VideoPlayerDialog extends StatefulWidget {
  const _VideoPlayerDialog({required this.video, this.scopeId});

  final VideoData video;
  final String? scopeId;

  @override
  State<_VideoPlayerDialog> createState() => _VideoPlayerDialogState();
}

class _VideoPlayerDialogState extends State<_VideoPlayerDialog> {
  late VideoPlayerController _controller;
  bool _isInitialized = false;
  bool _markedWatched = false;

  @override
  void initState() {
    super.initState();
    _initializeVideo();
  }

  Future<void> _initializeVideo() async {
    _controller = VideoPlayerController.asset(widget.video.videoPath!);
    try {
      await _controller.initialize();
      _controller.addListener(_onControllerValueChanged);
      if (mounted) {
        setState(() {
          _isInitialized = true;
        });
      }
    } catch (e) {
      if (mounted) {
        setState(() {
          _isInitialized = false;
        });
        showPillSnackBar(context, 'Erro ao carregar vídeo: $e');
      }
    }
  }

  void _onControllerValueChanged() {
    if (_markedWatched) return;
    final value = _controller.value;
    if (!value.isInitialized || value.duration == Duration.zero) return;
    if (value.position >= value.duration - const Duration(milliseconds: 300)) {
      _markedWatched = true;
      markVideoWatched(widget.scopeId, widget.video.id);
    }
  }

  @override
  void dispose() {
    _controller.removeListener(_onControllerValueChanged);
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final size = MediaQuery.sizeOf(context);
    return Dialog(
      backgroundColor: Colors.transparent,
      insetPadding: const EdgeInsets.all(16),
      child: Container(
        decoration: BoxDecoration(
          color: VideoScreen._accentPink.withValues(alpha: 0.15),
          borderRadius: BorderRadius.circular(24),
          border: Border.all(color: VideoScreen._accentPink, width: 3),
        ),
        child: ClipRRect(
          borderRadius: BorderRadius.circular(21),
          child: SizedBox(
            width: size.width * 0.9,
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                // Video player
                if (_isInitialized)
                  AspectRatio(
                    aspectRatio: _controller.value.aspectRatio,
                    child: VideoPlayer(_controller),
                  )
                else
                  const AspectRatio(
                    aspectRatio: 16 / 9,
                    child: Center(
                      child: CircularProgressIndicator(
                        valueColor: AlwaysStoppedAnimation<Color>(
                          VideoScreen._accentPink,
                        ),
                      ),
                    ),
                  ),
                // Video controls with close button
                if (_isInitialized)
                  _VideoControls(
                    controller: _controller,
                    videoPath: widget.video.videoPath!,
                    videoId: widget.video.id,
                    scopeId: widget.scopeId,
                    onClose: () => Navigator.of(context).pop(),
                  ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

class _VideoControls extends StatefulWidget {
  const _VideoControls({
    required this.controller,
    required this.videoPath,
    required this.videoId,
    required this.onClose,
    this.scopeId,
  });

  final VideoPlayerController controller;
  final String videoPath;
  final int videoId;
  final String? scopeId;
  final VoidCallback onClose;

  @override
  State<_VideoControls> createState() => _VideoControlsState();
}

class _VideoControlsState extends State<_VideoControls> {
  @override
  void initState() {
    super.initState();
    widget.controller.addListener(_onControllerUpdate);
  }

  @override
  void dispose() {
    widget.controller.removeListener(_onControllerUpdate);
    super.dispose();
  }

  void _onControllerUpdate() {
    if (mounted) {
      setState(() {});
    }
  }

  void _seekBy(Duration offset) {
    final position = widget.controller.value.position;
    final duration = widget.controller.value.duration;
    var target = position + offset;
    if (target < Duration.zero) target = Duration.zero;
    if (target > duration) target = duration;
    widget.controller.seekTo(target);
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
      color: VideoScreen._accentPink.withValues(alpha: 0.15),
      child: Row(
        children: [
          // Control buttons
          Expanded(
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                // Progress bar
                VideoProgressIndicator(
                  widget.controller,
                  allowScrubbing: true,
                  colors: const VideoProgressColors(
                    playedColor: VideoScreen._teal,
                    bufferedColor: Colors.white54,
                    backgroundColor: Colors.white24,
                  ),
                ),
                const SizedBox(height: 4),
                // Control buttons
                Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    IconButton(
                      icon: const Icon(
                        Icons.replay_10_rounded,
                        color: Colors.white,
                      ),
                      tooltip: 'Retroceder 10s',
                      onPressed: () => _seekBy(const Duration(seconds: -10)),
                    ),
                    IconButton(
                      icon: Icon(
                        widget.controller.value.isPlaying
                            ? Icons.pause
                            : Icons.play_arrow,
                        color: Colors.white,
                      ),
                      onPressed: () {
                        if (widget.controller.value.isPlaying) {
                          widget.controller.pause();
                        } else {
                          widget.controller.play();
                        }
                      },
                    ),
                    IconButton(
                      icon: const Icon(
                        Icons.forward_10_rounded,
                        color: Colors.white,
                      ),
                      tooltip: 'Avançar 10s',
                      onPressed: () => _seekBy(const Duration(seconds: 10)),
                    ),
                    IconButton(
                      icon: const Icon(Icons.fullscreen, color: Colors.white),
                      onPressed: () {
                        // Liberta todos os decodificadores de prévia antes
                        // de abrir o player em fullscreen.
                        _evictAllVideoControllers();
                        Navigator.of(context).pop();
                        Navigator.of(context).push(
                          MaterialPageRoute(
                            builder: (context) => _FullscreenVideoPlayer(
                              videoPath: widget.videoPath,
                              videoId: widget.videoId,
                              scopeId: widget.scopeId,
                            ),
                            fullscreenDialog: true,
                          ),
                        );
                      },
                    ),
                  ],
                ),
              ],
            ),
          ),
          // Close button
          IconButton(
            icon: const Icon(Icons.close, color: Colors.white),
            onPressed: widget.onClose,
          ),
        ],
      ),
    );
  }
}

class _FullscreenVideoPlayer extends StatefulWidget {
  const _FullscreenVideoPlayer({
    required this.videoPath,
    required this.videoId,
    this.scopeId,
  });

  final String videoPath;
  final int videoId;
  final String? scopeId;

  @override
  State<_FullscreenVideoPlayer> createState() => _FullscreenVideoPlayerState();
}

class _FullscreenVideoPlayerState extends State<_FullscreenVideoPlayer> {
  late VideoPlayerController _controller;
  bool _isInitialized = false;
  bool _markedWatched = false;

  @override
  void initState() {
    super.initState();
    SystemChrome.setPreferredOrientations([
      DeviceOrientation.landscapeLeft,
      DeviceOrientation.landscapeRight,
    ]);
    _initializeVideo();
  }

  Future<void> _initializeVideo() async {
    _controller = VideoPlayerController.asset(widget.videoPath);
    try {
      await _controller.initialize();
      _controller.addListener(_onControllerUpdate);
      if (mounted) {
        setState(() {
          _isInitialized = true;
        });
      }
    } catch (e) {
      if (mounted) {
        setState(() {
          _isInitialized = false;
        });
        showPillSnackBar(context, 'Erro ao carregar vídeo: $e');
      }
    }
  }

  void _onControllerUpdate() {
    if (!_markedWatched) {
      final value = _controller.value;
      if (value.isInitialized &&
          value.duration != Duration.zero &&
          value.position >=
              value.duration - const Duration(milliseconds: 300)) {
        _markedWatched = true;
        markVideoWatched(widget.scopeId, widget.videoId);
      }
    }
    if (mounted) {
      setState(() {});
    }
  }

  void _seekBy(Duration offset) {
    final position = _controller.value.position;
    final duration = _controller.value.duration;
    var target = position + offset;
    if (target < Duration.zero) target = Duration.zero;
    if (target > duration) target = duration;
    _controller.seekTo(target);
  }

  @override
  void dispose() {
    SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
    _controller.removeListener(_onControllerUpdate);
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.black,
      body: Center(
        child: _isInitialized
            ? AspectRatio(
                aspectRatio: _controller.value.aspectRatio,
                child: VideoPlayer(_controller),
              )
            : const CircularProgressIndicator(
                valueColor: AlwaysStoppedAnimation<Color>(
                  VideoScreen._accentPink,
                ),
              ),
      ),
      floatingActionButton: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          if (_isInitialized)
            Row(
              mainAxisSize: MainAxisSize.min,
              children: [
                FloatingActionButton(
                  heroTag: 'rewind',
                  mini: true,
                  backgroundColor: VideoScreen._teal,
                  onPressed: () => _seekBy(const Duration(seconds: -10)),
                  child: const Icon(
                    Icons.replay_10_rounded,
                    color: Colors.white,
                  ),
                ),
                const SizedBox(width: 16),
                FloatingActionButton(
                  heroTag: 'play_pause',
                  backgroundColor: VideoScreen._teal,
                  onPressed: () {
                    if (_controller.value.isPlaying) {
                      _controller.pause();
                    } else {
                      _controller.play();
                    }
                  },
                  child: Icon(
                    _controller.value.isPlaying
                        ? Icons.pause
                        : Icons.play_arrow,
                    color: Colors.white,
                  ),
                ),
                const SizedBox(width: 16),
                FloatingActionButton(
                  heroTag: 'forward',
                  mini: true,
                  backgroundColor: VideoScreen._teal,
                  onPressed: () => _seekBy(const Duration(seconds: 10)),
                  child: const Icon(
                    Icons.forward_10_rounded,
                    color: Colors.white,
                  ),
                ),
              ],
            ),
          if (_isInitialized) const SizedBox(height: 16),
          FloatingActionButton(
            heroTag: 'exit_fullscreen',
            backgroundColor: VideoScreen._accentPink,
            onPressed: () => Navigator.of(context).pop(),
            child: const Icon(Icons.fullscreen_exit, color: Colors.white),
          ),
        ],
      ),
    );
  }
}
