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

import '../../core/contracts/trakt/trakt_calendar_entry.dart';
import '../../providers/di_providers.dart';
import '../../providers/trakt_calendar_provider.dart';
import '../../shared/utils/media_nav.dart';
import '../../shared/widgets/app_loading_ring.dart';
import '../../shared/widgets/app_error_state.dart';
import '../../shared/widgets/app_sliver_header.dart';
import '../../shared/widgets/page_background.dart';
import '../../shared/widgets/pill_tab_bar.dart';
import '../../shared/widgets/smart_image.dart';

const _kTabs = ['全部', '剧集', '电影'];

class TraktCalendarPage extends ConsumerStatefulWidget {
  const TraktCalendarPage({super.key});

  @override
  ConsumerState<TraktCalendarPage> createState() => _TraktCalendarPageState();
}

class _TraktCalendarPageState extends ConsumerState<TraktCalendarPage> {
  int _tabIndex = 0;

  void _onTabChanged(int index) {
    if (index == _tabIndex) return;
    setState(() => _tabIndex = index);
    final filter = switch (index) {
      1 => TraktCalendarFilter.shows,
      2 => TraktCalendarFilter.movies,
      _ => TraktCalendarFilter.all,
    };
    ref.read(traktCalendarFilterProvider.notifier).state = filter;
  }

  @override
  Widget build(BuildContext context) {
    final asyncEntries = ref.watch(traktCalendarProvider);

    return Scaffold(
      extendBodyBehindAppBar: true,
      backgroundColor: Colors.transparent,
      body: Stack(
        children: [
          const Positioned.fill(child: PageBackground()),
          RefreshIndicator(
            onRefresh: () async {
              ref.invalidate(traktCalendarProvider);
              await ref.read(traktCalendarProvider.future);
            },
            child: CustomScrollView(
              slivers: [
                AppSliverHeader(
                  title: '日历',
                  automaticallyImplyLeading: false,
                  bottom: PreferredSize(
                    preferredSize: const Size.fromHeight(48),
                    child: Padding(
                      padding: const EdgeInsets.fromLTRB(16, 0, 16, 8),
                      child: PillTabBar(
                        tabs: _kTabs,
                        selectedIndex: _tabIndex,
                        onSelect: _onTabChanged,
                      ),
                    ),
                  ),
                ),
                asyncEntries.when(
                  loading: () => const SliverFillRemaining(
                    child: Center(child: AppLoadingRing()),
                  ),
                  error: (e, _) => SliverFillRemaining(
                    child: AppErrorState(
                      title: '加载失败',
                      message: '$e',
                      onRetry: () => ref.invalidate(traktCalendarProvider),
                    ),
                  ),
                  data: (entries) {
                    if (entries.isEmpty) {
                      return const SliverFillRemaining(
                        child: AppErrorState(
                          title: '暂无内容',
                          message: '未来 7 天没有新内容',
                          icon: Icons.calendar_today_outlined,
                        ),
                      );
                    }
                    final groups = groupByDate(entries);
                    return SliverList(
                      delegate: SliverChildBuilderDelegate(
                        (context, index) =>
                            _buildGroupItem(context, groups, index),
                        childCount: groups.fold<int>(
                          0,
                          (sum, g) => sum + 1 + g.entries.length,
                        ),
                      ),
                    );
                  },
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildGroupItem(
    BuildContext context,
    List<CalendarDateGroup> groups,
    int flatIndex,
  ) {
    var cursor = 0;
    for (final group in groups) {
      if (flatIndex == cursor) {
        return _DateHeader(label: group.label, count: group.entries.length);
      }
      cursor++;
      final entryIndex = flatIndex - cursor;
      if (entryIndex < group.entries.length) {
        return _CalendarEntryTile(entry: group.entries[entryIndex]);
      }
      cursor += group.entries.length;
    }
    return const SizedBox.shrink();
  }
}

class _DateHeader extends StatelessWidget {
  final String label;
  final int count;

  const _DateHeader({required this.label, required this.count});

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    return Padding(
      padding: const EdgeInsets.fromLTRB(24, 20, 24, 8),
      child: Row(
        children: [
          Text(
            label,
            style: theme.textTheme.titleSmall?.copyWith(
              fontWeight: FontWeight.w600,
            ),
          ),
          const SizedBox(width: 8),
          Text(
            '$count',
            style: theme.textTheme.labelSmall?.copyWith(
              color: theme.colorScheme.onSurface.withValues(alpha: 0.45),
            ),
          ),
        ],
      ),
    );
  }
}

class _CalendarEntryTile extends ConsumerWidget {
  final TraktCalendarEntry entry;

  const _CalendarEntryTile({required this.entry});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final theme = Theme.of(context);
    final hasTmdb = entry.tmdbId != null && entry.tmdbId! > 0;
    final airTime = _formatAirTime(entry.firstAired.toLocal());

    String? networkName;
    if (hasTmdb) {
      final TmdbMediaKey key = (
        tmdbId: entry.tmdbId!.toString(),
        mediaType: entry.mediaType,
      );
      final enriched = ref.watch(tmdbEnrichedDetailProvider(key)).value;
      networkName = enriched?.networks.firstOrNull?.name;
    }

    return InkWell(
      onTap: hasTmdb
          ? () => goTmdbDetail(
              context,
              tmdbId: entry.tmdbId!,
              mediaType: entry.mediaType,
            )
          : null,
      child: Padding(
        padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 8),
        child: Row(
          children: [
            SizedBox(
              width: 48,
              height: 72,
              child: SmartImage(
                url: entry.posterUrl,
                borderRadius: 6,
                fallbackIcon: entry.type == 'movie'
                    ? Icons.movie_outlined
                    : Icons.tv_outlined,
              ),
            ),
            const SizedBox(width: 14),
            Expanded(
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Text(
                    entry.displayTitle,
                    maxLines: 1,
                    overflow: TextOverflow.ellipsis,
                    style: theme.textTheme.bodyMedium?.copyWith(
                      fontWeight: FontWeight.w500,
                    ),
                  ),
                  const SizedBox(height: 3),
                  Text(
                    [
                      entry.displaySubtitle,
                      airTime,
                      if (networkName != null) networkName,
                    ].where((s) => s.isNotEmpty).join(' · '),
                    maxLines: 1,
                    overflow: TextOverflow.ellipsis,
                    style: theme.textTheme.bodySmall?.copyWith(
                      color: theme.colorScheme.onSurface.withValues(
                        alpha: 0.55,
                      ),
                    ),
                  ),
                ],
              ),
            ),
            if (!hasTmdb)
              Icon(
                Icons.link_off,
                size: 16,
                color: theme.colorScheme.onSurface.withValues(alpha: 0.25),
              ),
          ],
        ),
      ),
    );
  }

  static String _formatAirTime(DateTime local) {
    return '${local.hour.toString().padLeft(2, '0')}:'
        '${local.minute.toString().padLeft(2, '0')}';
  }
}
