import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

import '../../../../core/contracts/library.dart';
import '../../../../providers/di_providers.dart';
import '../../../../providers/tmdb_settings_provider.dart';
import '../../../../shared/utils/emby_ticks.dart';
import '../../../../shared/utils/format_utils.dart';
import '../../../../shared/utils/tmdb_episode_helpers.dart';
import '../../../../shared/utils/tmdb_key_utils.dart';
import '../../../../shared/widgets/app_inline_alert.dart';
import '../../../../shared/widgets/app_loading_ring.dart';
import '../../../../shared/widgets/episode_thumb.dart';
import '../../../../shared/widgets/season_selector.dart';
import '../player_panel_shell.dart';

const Color _kActiveColor = Color(0xFF4FA8FF);

class EpisodePanelBody extends ConsumerStatefulWidget {
  final String seriesId;
  final String? initialSeasonId;
  final String currentEpisodeId;
  final ValueChanged<EmbyRawItem> onEpisodeSelected;


  final String serverId;
  final String baseUrl;
  final String token;

  const EpisodePanelBody({
    super.key,
    required this.seriesId,
    required this.currentEpisodeId,
    required this.onEpisodeSelected,
    required this.serverId,
    required this.baseUrl,
    required this.token,
    this.initialSeasonId,
  });

  @override
  ConsumerState<EpisodePanelBody> createState() => EpisodePanelBodyState();
}


class EpisodePanelBodyState extends ConsumerState<EpisodePanelBody> {
  String? _selectedSeasonId;
  bool _loadStarted = false;

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


  void ensureLoaded() {
    if (_loadStarted) return;
    _loadStarted = true;
    if (mounted) setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    if (!_loadStarted) {
      return const SizedBox.shrink();
    }

    final serverId = widget.serverId;
    if (serverId.isEmpty) return const SizedBox.shrink();

    final seasonsAsync = ref.watch(
      seriesSeasonsDataProvider((
        serverId: serverId,
        seriesId: widget.seriesId,
      )),
    );

    return seasonsAsync.when(
      loading: _loading,
      error: (_, _) => _error(),
      data: (seasons) {
        if (seasons.isEmpty) return _empty('暂无可用季');
        final effectiveSeasonId = _resolveSeasonId(seasons);
        final effectiveSeason = seasons.firstWhere(
          (s) => s.Id == effectiveSeasonId,
          orElse: () => seasons.first,
        );
        return Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            if (seasons.length > 1) ...[
              Padding(
                padding: const EdgeInsets.symmetric(
                  horizontal: 12,
                  vertical: 8,
                ),
                child: Align(
                  alignment: Alignment.centerLeft,
                  child: SeasonSelector(
                    seasons: seasons,
                    selectedId: effectiveSeasonId,
                    onSelect: (seasonId) {
                      setState(() => _selectedSeasonId = seasonId);
                    },
                  ),
                ),
              ),
              const Divider(color: kPanelDivider, height: 1),
            ],
            Flexible(
              child: _EpisodeList(
                seriesId: widget.seriesId,
                seasonId: effectiveSeasonId,
                seasonNumber: seasonNumberFrom(effectiveSeason),
                currentEpisodeId: widget.currentEpisodeId,
                serverId: widget.serverId,
                baseUrl: widget.baseUrl,
                token: widget.token,
                onSelected: widget.onEpisodeSelected,
              ),
            ),
          ],
        );
      },
    );
  }

  String _resolveSeasonId(List<EmbyRawSeason> seasons) {
    final selected = _selectedSeasonId;
    if (selected != null && seasons.any((s) => s.Id == selected)) {
      return selected;
    }
    final initial = widget.initialSeasonId;
    if (initial != null && seasons.any((s) => s.Id == initial)) {
      return initial;
    }
    return seasons.first.Id;
  }

  Widget _loading() => const Padding(
    padding: EdgeInsets.symmetric(vertical: 32),
    child: Center(child: AppLoadingRing(size: 22, color: Colors.white)),
  );

  Widget _empty(String text) => Padding(
    padding: const EdgeInsets.symmetric(vertical: 32),
    child: Center(
      child: Text(
        text,
        style: const TextStyle(color: Colors.white54, fontSize: 13),
      ),
    ),
  );

  Widget _error() => const Padding(
    padding: EdgeInsets.symmetric(vertical: 32),
    child: AppInlineAlert(message: '选集加载失败'),
  );
}

class _EpisodeList extends ConsumerStatefulWidget {
  final String seriesId;
  final String seasonId;
  final int? seasonNumber;
  final String? currentEpisodeId;
  final String serverId;
  final String baseUrl;
  final String token;
  final ValueChanged<EmbyRawItem> onSelected;

  const _EpisodeList({
    required this.seriesId,
    required this.seasonId,
    required this.seasonNumber,
    required this.currentEpisodeId,
    required this.serverId,
    required this.baseUrl,
    required this.token,
    required this.onSelected,
  });

  @override
  ConsumerState<_EpisodeList> createState() => _EpisodeListState();
}

class _EpisodeListState extends ConsumerState<_EpisodeList> {
  final ScrollController _scrollController = ScrollController();
  bool _hasScrolledToActive = false;

  static const _itemHeight = 76.0;

  @override
  void didUpdateWidget(covariant _EpisodeList oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (oldWidget.seasonId != widget.seasonId ||
        oldWidget.currentEpisodeId != widget.currentEpisodeId) {
      _hasScrolledToActive = false;
    }
  }

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

  void _scrollToActive(List<EmbyRawItem> episodes) {
    if (_hasScrolledToActive || widget.currentEpisodeId == null) return;
    final idx = episodes.indexWhere((e) => e.Id == widget.currentEpisodeId);
    if (idx < 0) return;
    _hasScrolledToActive = true;
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (!mounted || !_scrollController.hasClients) return;
      final viewport = _scrollController.position.viewportDimension;
      final target = idx * _itemHeight - (viewport - _itemHeight) / 2;
      final clamped = target.clamp(
        0.0,
        _scrollController.position.maxScrollExtent,
      );
      _scrollController.jumpTo(clamped);
    });
  }

  @override
  Widget build(BuildContext context) {
    final serverId = widget.serverId;
    final episodesAsync = ref.watch(
      seriesEpisodesDataProvider((
        serverId: serverId,
        seriesId: widget.seriesId,
        seasonId: widget.seasonId,
      )),
    );

    final tmdbSettings = ref.watch(tmdbSettingsProvider).value;
    final canRequest = tmdbSettings?.canRequest ?? false;
    String tmdbSeriesId = '';
    if (canRequest) {
      final seriesItem = ref
          .watch(
            mediaDetailDataProvider((
              serverId: serverId,
              itemId: widget.seriesId,
            )),
          )
          .value
          ?.base;
      if (seriesItem != null) tmdbSeriesId = tmdbIdFromItem(seriesItem);
    }
    final canUseTmdbSeason =
        canRequest && tmdbSeriesId.isNotEmpty && widget.seasonNumber != null;
    final tmdbSeason = canUseTmdbSeason
        ? ref
              .watch(
                tmdbSeasonDetailProvider((
                  tmdbId: tmdbSeriesId,
                  seasonNumber: widget.seasonNumber!,
                )),
              )
              .value
        : null;
    final tmdbStillUrls = tmdbStillUrlsByEpisode(
      tmdbSeason,
      tmdbSettings?.effectiveImageBaseUrl,
    );

    return episodesAsync.when(
      loading: () => const Padding(
        padding: EdgeInsets.symmetric(vertical: 32),
        child: Center(child: AppLoadingRing(size: 22, color: Colors.white)),
      ),
      error: (_, _) => const Padding(
        padding: EdgeInsets.symmetric(vertical: 32),
        child: AppInlineAlert(message: '选集加载失败'),
      ),
      data: (episodes) {
        if (episodes.isEmpty) {
          return const Padding(
            padding: EdgeInsets.symmetric(vertical: 32),
            child: Center(
              child: Text(
                '暂无分集',
                style: TextStyle(color: Colors.white54, fontSize: 13),
              ),
            ),
          );
        }
        _scrollToActive(episodes);
        return ListView.separated(
          controller: _scrollController,
          shrinkWrap: true,
          padding: const EdgeInsets.symmetric(vertical: 4),
          itemCount: episodes.length,
          separatorBuilder: (_, _) => const Divider(
            color: kPanelDivider,
            height: 1,
            indent: 12,
            endIndent: 12,
          ),
          itemBuilder: (_, i) {
            final ep = episodes[i];
            final tmdbStillUrl = ep.IndexNumber == null
                ? null
                : tmdbStillUrls[ep.IndexNumber];
            return _EpisodeTile(
              episode: ep,
              seriesId: widget.seriesId,
              tmdbStillUrl: tmdbStillUrl,
              isActive: ep.Id == widget.currentEpisodeId,
              baseUrl: widget.baseUrl,
              token: widget.token,
              onTap: () => widget.onSelected(ep),
            );
          },
        );
      },
    );
  }
}

class _EpisodeTile extends StatelessWidget {
  final EmbyRawItem episode;
  final String seriesId;
  final String? tmdbStillUrl;
  final bool isActive;
  final String baseUrl;
  final String token;
  final VoidCallback onTap;

  const _EpisodeTile({
    required this.episode,
    required this.seriesId,
    required this.tmdbStillUrl,
    required this.isActive,
    required this.baseUrl,
    required this.token,
    required this.onTap,
  });

  @override
  Widget build(BuildContext context) {
    final ep = formatEpisodeNumber(episode.IndexNumber) ?? '';
    final runtime = episode.RunTimeTicks != null
        ? '${(episode.RunTimeTicks! / kTicksPerMinute).round()} 分钟'
        : '';
    final progress = playbackProgress(episode);

    return InkWell(
      onTap: isActive ? null : onTap,
      child: Padding(
        padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
        child: Row(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            ClipRRect(
              borderRadius: BorderRadius.circular(4),
              child: Container(
                width: 96,
                height: 54,
                color: Colors.white12,
                child: Stack(
                  fit: StackFit.expand,
                  children: [
                    EpisodeThumb(
                      episode: episode,
                      seriesId: seriesId,
                      baseUrl: baseUrl,
                      token: token,
                      tmdbStillUrl: tmdbStillUrl,
                      maxWidth: 240,
                    ),
                    if (isActive)
                      Container(
                        color: Colors.black54,
                        alignment: Alignment.center,
                        child: const Icon(
                          Icons.play_arrow,
                          color: Colors.white,
                          size: 28,
                        ),
                      ),
                    if (progress > 0)
                      Positioned(
                        left: 0,
                        right: 0,
                        bottom: 0,
                        child: LinearProgressIndicator(
                          value: progress,
                          minHeight: 2,
                          backgroundColor: Colors.white24,
                          valueColor: const AlwaysStoppedAnimation<Color>(
                            _kActiveColor,
                          ),
                        ),
                      ),
                  ],
                ),
              ),
            ),
            const SizedBox(width: 10),
            Expanded(
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                mainAxisSize: MainAxisSize.min,
                children: [
                  Row(
                    children: [
                      if (ep.isNotEmpty) ...[
                        Container(
                          padding: const EdgeInsets.symmetric(
                            horizontal: 6,
                            vertical: 2,
                          ),
                          decoration: BoxDecoration(
                            color: isActive ? _kActiveColor : Colors.white12,
                            borderRadius: BorderRadius.circular(3),
                          ),
                          child: Text(
                            ep,
                            style: const TextStyle(
                              color: Colors.white,
                              fontSize: 11,
                              fontWeight: FontWeight.w600,
                            ),
                          ),
                        ),
                        const SizedBox(width: 6),
                      ],
                      Expanded(
                        child: Text(
                          episode.Name,
                          maxLines: 1,
                          overflow: TextOverflow.ellipsis,
                          style: TextStyle(
                            color: isActive ? _kActiveColor : Colors.white,
                            fontSize: 13,
                            fontWeight: FontWeight.w500,
                          ),
                        ),
                      ),
                    ],
                  ),
                  const SizedBox(height: 4),
                  if (runtime.isNotEmpty)
                    Text(
                      runtime,
                      style: const TextStyle(
                        color: Colors.white54,
                        fontSize: 11,
                      ),
                    ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}
