import 'dart:async';

import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:forui/forui.dart';

import '../../core/contracts/library.dart';
import '../theme/app_theme.dart';
import '../utils/emby_ticks.dart';
import '../utils/format_utils.dart';
import 'auto_dismiss_menu.dart';
import 'card_progress_bar.dart';
import 'smart_image.dart';

enum MediaCardVariant { poster, landscape }

class MediaPosterCard extends StatefulWidget {
  final EmbyRawItem item;
  final String? imageUrl;
  final VoidCallback? onTap;
  final double width;
  final MediaCardVariant variant;
  final bool showHoverPlayIcon;
  final bool enableContextMenu;
  final bool? isFavoriteOverride;
  final bool? isPlayedOverride;
  final VoidCallback? onAddFavorite;
  final VoidCallback? onMarkPlayed;
  final VoidCallback? onHideFromResume;
  final bool favoriteLoading;
  final bool playedLoading;
  final bool hideFromResumeLoading;
  final bool showUnplayedCountBadge;
  final bool isActive;
  final String? fallbackImageUrl;
  final String? preloadImageUrl;
  final Map<String, String>? imageHeaders;


  final Color? textColor;

  const MediaPosterCard({
    super.key,
    required this.item,
    required this.imageUrl,
    this.onTap,
    this.width = 160,
    this.variant = MediaCardVariant.poster,
    this.showHoverPlayIcon = true,
    this.enableContextMenu = false,
    this.isFavoriteOverride,
    this.isPlayedOverride,
    this.onAddFavorite,
    this.onMarkPlayed,
    this.onHideFromResume,
    this.favoriteLoading = false,
    this.playedLoading = false,
    this.hideFromResumeLoading = false,
    this.showUnplayedCountBadge = true,
    this.isActive = false,
    this.fallbackImageUrl,
    this.preloadImageUrl,
    this.imageHeaders,
    this.textColor,
  });

  @override
  State<MediaPosterCard> createState() => _MediaPosterCardState();
}

class _MediaPosterCardState extends State<MediaPosterCard> {
  bool _hovered = false;
  String? _preloadedImageUrl;

  bool get _isFavorite =>
      widget.isFavoriteOverride ?? (widget.item.UserData?.IsFavorite ?? false);

  bool get _isPlayed =>
      widget.isPlayedOverride ?? (widget.item.UserData?.Played ?? false);

  double get _aspectRatio =>
      widget.variant == MediaCardVariant.landscape ? 16 / 9 : 0.66;

  String? _subtitleText() {
    final item = widget.item;
    if (widget.variant == MediaCardVariant.landscape) {
      if (item.Type == 'Episode' && item.IndexNumber != null) {
        final season = _seasonNumber(item);
        final epLabel = formatEpisodeNumber(item.IndexNumber)!;
        final locator = season != null && season > 1
            ? '${formatSeasonNumber(season)} $epLabel'
            : epLabel;
        return [
          locator,
          item.Name,
        ].where((segment) => segment.isNotEmpty).join(' · ');
      }
      if (item.Type == 'Episode') {
        final seasonLabel = _seasonLabel(item);
        if (seasonLabel != null) {
          return [
            seasonLabel,
            item.Name,
          ].where((segment) => segment.isNotEmpty).join(' · ');
        }
      }
      if (item.ProductionYear != null) return '${item.ProductionYear}';
      return null;
    }
    if (item.Type == 'Episode' && item.SeriesName != null) {
      final season = item.SeasonName ?? '';
      final episode = formatEpisodeNumber(item.IndexNumber) ?? '';
      return [
        item.SeriesName,
        season,
        episode,
      ].where((segment) => segment != null && segment.isNotEmpty).join(' · ');
    }
    if (item.ProductionYear != null) return '${item.ProductionYear}';
    return null;
  }


  int? _seasonNumber(EmbyRawItem item) =>
      (item.extra['ParentIndexNumber'] as num?)?.toInt();


  String? _seasonLabel(EmbyRawItem item) {
    final name = item.SeasonName;
    if (name != null && name.isNotEmpty) return name;
    final season = (item.extra['ParentIndexNumber'] as num?)?.toInt();
    if (season != null) return formatSeasonNumber(season);
    return null;
  }

  String get _displayTitle {
    if (widget.variant == MediaCardVariant.landscape) {
      return widget.item.SeriesName ?? widget.item.Name;
    }
    return widget.item.Name;
  }

  List<FItem> _contextMenuItems() => [
    if (widget.onAddFavorite != null)
      FItem(
        prefix: Icon(
          _isFavorite ? Icons.favorite : Icons.favorite_border,
          size: 16,
        ),
        enabled: !widget.favoriteLoading,
        title: Text(_isFavorite ? '取消收藏' : '添加到收藏'),
        onPress: () => widget.onAddFavorite?.call(),
      ),
    if (widget.onMarkPlayed != null)
      FItem(
        prefix: Icon(
          _isPlayed ? Icons.check_circle : Icons.check_circle_outline,
          size: 16,
        ),
        enabled: !widget.playedLoading,
        title: Text(_isPlayed ? '取消已观看' : '标记为已观看'),
        onPress: () => widget.onMarkPlayed?.call(),
      ),
    if (widget.onHideFromResume != null)
      FItem(
        prefix: const Icon(Icons.visibility_off_outlined, size: 16),
        enabled: !widget.hideFromResumeLoading,
        title: const Text('从“继续观看”中移除'),
        onPress: () => widget.onHideFromResume?.call(),
      ),
  ];

  void _preloadImage() {
    final url = widget.preloadImageUrl;
    if (url == null || url.isEmpty || _preloadedImageUrl == url) return;
    _preloadedImageUrl = url;
    var logicalWidth = widget.width;
    if (!logicalWidth.isFinite || logicalWidth <= 0) {
      logicalWidth = context.size?.width ?? 0;
    }
    final scaledWidth = logicalWidth * MediaQuery.devicePixelRatioOf(context);
    final memCacheWidth = scaledWidth.isFinite && scaledWidth > 0
        ? scaledWidth.ceil()
        : null;
    unawaited(
      precacheImage(
        ResizeImage.resizeIfNeeded(
          memCacheWidth,
          null,
          CachedNetworkImageProvider(url, headers: widget.imageHeaders),
        ),
        context,
        onError: (_, _) {},
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    final tokens = context.appTokens;
    final progress = playbackProgress(widget.item);
    final unplayed = widget.item.UserData?.UnplayedItemCount ?? 0;
    final showUnplayed = widget.showUnplayedCountBadge && unplayed > 0;
    final resolvedImageUrl = widget.imageUrl ?? widget.fallbackImageUrl;
    final radius = tokens.posterRadius;
    final remainingLabel = formatRemainingLabel(widget.item);

    final subtitleText = _subtitleText();

    final menuItems = widget.enableContextMenu ? _contextMenuItems() : <FItem>[];
    final hasMenu = menuItems.isNotEmpty;

    Widget content = SizedBox(
      width: widget.width,
      child: MouseRegion(
        onEnter: (_) {
          _preloadImage();
          setState(() => _hovered = true);
        },
        onExit: (_) => setState(() => _hovered = false),
        child: GestureDetector(
          onTap: widget.onTap == null
              ? null
              : () {
                  _preloadImage();
                  widget.onTap!();
                },
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            mainAxisSize: MainAxisSize.min,
            children: [
              Flexible(
                child: AnimatedOpacity(
                  opacity: _hovered ? 0.85 : 1.0,
                  duration: const Duration(milliseconds: 160),
                  child: Stack(
                    children: [
                      SmartImage(
                        url: resolvedImageUrl,
                        aspectRatio: _aspectRatio,
                        borderRadius: radius,
                        httpHeaders: widget.imageHeaders,
                      ),
                      if (widget.showHoverPlayIcon)
                        Positioned.fill(
                          child: AnimatedOpacity(
                            opacity: _hovered ? 1.0 : 0.0,
                            duration: const Duration(milliseconds: 160),
                            child: ClipRRect(
                              borderRadius: BorderRadius.circular(radius),
                              child: Container(
                                color: Colors.black.withValues(alpha: 0.3),
                                child: Center(
                                  child: Column(
                                    mainAxisSize: MainAxisSize.min,
                                    children: [
                                      const Icon(
                                        Icons.play_arrow_rounded,
                                        size: 32,
                                        color: Colors.white,
                                      ),
                                      if (remainingLabel != null) ...[
                                        const SizedBox(height: 4),
                                        Text(
                                          remainingLabel,
                                          style: const TextStyle(
                                            color: Colors.white,
                                            fontSize: 11,
                                            fontWeight: FontWeight.w500,
                                          ),
                                        ),
                                      ],
                                    ],
                                  ),
                                ),
                              ),
                            ),
                          ),
                        ),
                      if (progress > 0) CardProgressBar(progress: progress),
                      if (_isPlayed)
                        Positioned(
                          top: 6,
                          left: 6,
                          child: Icon(
                            Icons.check_circle,
                            size: 16,
                            color: Colors.white.withValues(alpha: 0.9),
                          ),
                        ),
                      if (_isFavorite)
                        Positioned(
                          top: 6,
                          right: showUnplayed ? 32 : 6,
                          child: Icon(
                            Icons.favorite,
                            size: 14,
                            color: Colors.white.withValues(alpha: 0.9),
                          ),
                        ),
                      if (showUnplayed)
                        Positioned(
                          top: 6,
                          right: 6,
                          child: Container(
                            padding: const EdgeInsets.symmetric(
                              horizontal: 5,
                              vertical: 2,
                            ),
                            decoration: BoxDecoration(
                              color: Colors.white,
                              borderRadius: BorderRadius.circular(2),
                            ),
                            child: Text(
                              '$unplayed',
                              style: const TextStyle(
                                color: Colors.black,
                                fontSize: 10,
                                fontWeight: FontWeight.w700,
                              ),
                            ),
                          ),
                        ),
                      if (widget.isActive)
                        Positioned(
                          left: 0,
                          right: 0,
                          bottom: 0,
                          child: Container(
                            height: 2,
                            decoration: BoxDecoration(
                              color: Colors.white,
                              borderRadius: BorderRadius.only(
                                bottomLeft: Radius.circular(radius),
                                bottomRight: Radius.circular(radius),
                              ),
                            ),
                          ),
                        ),
                    ],
                  ),
                ),
              ),
              const SizedBox(height: 10),
              Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                mainAxisSize: MainAxisSize.min,
                children: [
                  Text(
                    _displayTitle,
                    maxLines: 1,
                    overflow: TextOverflow.ellipsis,
                    style: theme.textTheme.bodyMedium?.copyWith(
                      fontWeight: FontWeight.w500,
                      color: widget.textColor,
                    ),
                  ),
                  if (subtitleText != null) ...[
                    const SizedBox(height: 2),
                    Text(
                      subtitleText,
                      maxLines: 1,
                      overflow: TextOverflow.ellipsis,
                      style: theme.textTheme.bodySmall?.copyWith(
                        color: widget.textColor != null
                            ? widget.textColor!.withValues(alpha: 0.55)
                            : tokens.mutedForeground,
                      ),
                    ),
                  ],
                ],
              ),
            ],
          ),
        ),
      ),
    );

    if (hasMenu) {
      content = FContextMenu(
        menuBuilder: autoDismissMenuBuilder,
        menu: [FItemGroup(children: menuItems)],
        child: content,
      );
    }
    return content;
  }
}
