import 'package:cached_network_image_ce/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:material_symbols_icons/symbols.dart';

import '../i18n/strings.g.dart';
import '../media/media_item.dart';
import '../media/media_item_types.dart';
import '../media/media_server_client.dart';
import '../services/image_cache_service.dart';
import '../utils/content_utils.dart';
import '../utils/formatters.dart';
import '../utils/layout_constants.dart';
import '../utils/media_image_helper.dart';
import 'app_icon.dart';
import 'optimized_media_image.dart' show blurArtwork;

class TvSpotlightBackground extends StatelessWidget {
  final MediaItem? item;
  final MediaServerClient? client;
  final bool hideSpoilers;
  final double contentBottom;
  final double? contentTop;
  final double? contentLeft;
  final VoidCallback? onPrimaryAction;
  final Widget? actions;
  final bool compact;
  final bool showPrimaryAction;
  final bool showInfo;

  const TvSpotlightBackground({
    super.key,
    required this.item,
    required this.client,
    this.hideSpoilers = false,
    this.contentBottom = 360,
    this.contentTop,
    this.contentLeft,
    this.onPrimaryAction,
    this.actions,
    this.compact = false,
    this.showPrimaryAction = true,
    this.showInfo = true,
  });

  double _scale(BuildContext context) => TvLayoutConstants.scaleOf(context);

  @override
  Widget build(BuildContext context) {
    final media = item;
    final colorScheme = Theme.of(context).colorScheme;
    final bgColor = Theme.of(context).scaffoldBackgroundColor;

    return AnimatedSwitcher(
      duration: const Duration(milliseconds: 280),
      switchInCurve: Curves.easeOutCubic,
      switchOutCurve: Curves.easeOutCubic,
      child: SizedBox.expand(
        key: ValueKey(media?.globalKey ?? 'empty_spotlight'),
        child: Stack(
          fit: StackFit.expand,
          children: [
            if (media != null) _buildArtwork(context, media) else ColoredBox(color: bgColor),
            DecoratedBox(
              decoration: BoxDecoration(
                gradient: LinearGradient(
                  begin: Alignment.centerLeft,
                  end: Alignment.centerRight,
                  colors: [bgColor.withValues(alpha: 0.86), bgColor.withValues(alpha: 0.32), Colors.transparent],
                  stops: const [0.0, 0.56, 1.0],
                ),
              ),
            ),
            DecoratedBox(
              decoration: BoxDecoration(
                gradient: LinearGradient(
                  begin: Alignment.topCenter,
                  end: Alignment.bottomCenter,
                  colors: [Colors.black.withValues(alpha: 0.45), Colors.transparent, bgColor.withValues(alpha: 0.96)],
                  stops: const [0.0, 0.38, 1.0],
                ),
              ),
            ),
            if (media != null && showInfo)
              Positioned(
                left: contentLeft ?? TvLayoutConstants.horizontalInset,
                right: MediaQuery.sizeOf(context).width * 0.43,
                top: contentTop,
                bottom: contentBottom,
                child: LayoutBuilder(
                  builder: (context, constraints) {
                    if (!constraints.hasBoundedHeight || constraints.maxHeight <= 0 || constraints.maxWidth <= 0) {
                      return Align(alignment: Alignment.bottomLeft, child: _buildInfo(context, media, colorScheme));
                    }

                    return Align(
                      alignment: Alignment.bottomLeft,
                      child: FittedBox(
                        fit: BoxFit.scaleDown,
                        alignment: Alignment.bottomLeft,
                        child: SizedBox(width: constraints.maxWidth, child: _buildInfo(context, media, colorScheme)),
                      ),
                    );
                  },
                ),
              ),
          ],
        ),
      ),
    );
  }

  Widget _buildArtwork(BuildContext context, MediaItem media) {
    final size = MediaQuery.sizeOf(context);
    final dpr = MediaImageHelper.effectiveDevicePixelRatio(context);
    final containerAspect = size.width / size.height;
    final artPath =
        media.heroArt(containerAspectRatio: containerAspect) ??
        media.grandparentArtPath ??
        media.artPath ??
        media.backgroundSquarePath ??
        media.thumbPath;
    final imageUrl = MediaImageHelper.getOptimizedImageUrl(
      client: client,
      thumbPath: artPath,
      maxWidth: size.width,
      maxHeight: size.height,
      devicePixelRatio: dpr,
      imageType: ImageType.art,
    );

    if (imageUrl.isEmpty) {
      return ColoredBox(color: Theme.of(context).colorScheme.surfaceContainerHighest);
    }

    final (_, memHeight) = MediaImageHelper.getMemCacheDimensions(
      displayWidth: (size.width * dpr).round(),
      displayHeight: (size.height * dpr).round(),
      imageType: ImageType.art,
    );

    return blurArtwork(
      CachedNetworkImage(
        imageUrl: imageUrl,
        cacheManager: PlexImageCacheManager.instance,
        fit: BoxFit.cover,
        memCacheHeight: memHeight,
        placeholder: (context, url) => ColoredBox(color: Theme.of(context).colorScheme.surfaceContainerHighest),
        errorBuilder: (context, error, stackTrace) =>
            ColoredBox(color: Theme.of(context).colorScheme.surfaceContainerHighest),
      ),
    );
  }

  Widget _buildInfo(BuildContext context, MediaItem media, ColorScheme colorScheme) {
    final scale = _scale(context);
    final shouldHideSpoiler = hideSpoilers && media.shouldHideSpoiler;
    final summary = shouldHideSpoiler ? null : media.summary;
    final title = media.grandparentTitle ?? media.displayTitle;

    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      mainAxisSize: MainAxisSize.min,
      children: [
        _buildLogoOrTitle(context, media, title),
        SizedBox(height: _sectionGap(scale)),
        _buildMetadataLine(context, media),
        if (summary != null && summary.isNotEmpty) ...[
          SizedBox(height: _sectionGap(scale)),
          Text(
            _summaryText(media, summary),
            maxLines: compact ? 2 : 4,
            overflow: TextOverflow.ellipsis,
            style: Theme.of(context).textTheme.bodyLarge?.copyWith(
              color: Colors.white.withValues(alpha: 0.78),
              fontSize: _summaryFontSize(scale),
              height: compact ? 1.34 : 1.45,
            ),
          ),
        ] else if (shouldHideSpoiler && media.isEpisode) ...[
          SizedBox(height: _sectionGap(scale)),
          Text(
            _episodePrefix(media) ?? media.title ?? '',
            maxLines: 2,
            overflow: TextOverflow.ellipsis,
            style: Theme.of(context).textTheme.bodyLarge?.copyWith(
              color: Colors.white.withValues(alpha: 0.72),
              fontSize: _summaryFontSize(scale),
              height: compact ? 1.34 : 1.45,
            ),
          ),
        ],
        if (showPrimaryAction || actions != null) ...[
          SizedBox(height: (compact ? 18 : 26) * scale),
          actions ?? _buildPrimaryAction(context, colorScheme, media),
        ],
      ],
    );
  }

  Widget _buildLogoOrTitle(BuildContext context, MediaItem media, String title) {
    final scale = _scale(context);
    final logoPath = media.clearLogoPath;
    if (logoPath == null || logoPath.isEmpty) return _buildTitle(context, title);

    final dpr = MediaImageHelper.effectiveDevicePixelRatio(context);
    final logoWidth = _logoWidth(scale);
    final logoHeight = _logoHeight(scale);
    final imageUrl = MediaImageHelper.getOptimizedImageUrl(
      client: client,
      thumbPath: logoPath,
      maxWidth: logoWidth,
      maxHeight: logoHeight,
      devicePixelRatio: dpr,
      imageType: ImageType.logo,
    );
    if (imageUrl.isEmpty) return _buildTitle(context, title);

    return SizedBox(
      width: logoWidth,
      height: logoHeight,
      child: blurArtwork(
        CachedNetworkImage(
          imageUrl: imageUrl,
          cacheManager: PlexImageCacheManager.instance,
          fit: BoxFit.contain,
          alignment: Alignment.centerLeft,
          memCacheWidth: (logoWidth * dpr).clamp(200, 1000).round(),
          placeholder: (context, url) => const SizedBox.shrink(),
          errorBuilder: (context, error, stackTrace) => _buildTitle(context, title),
        ),
        sigma: 10,
        clip: false,
      ),
    );
  }

  Widget _buildTitle(BuildContext context, String title) {
    final scale = _scale(context);
    return Text(
      title,
      maxLines: 2,
      overflow: TextOverflow.ellipsis,
      style: Theme.of(context).textTheme.displaySmall?.copyWith(
        color: Colors.white,
        fontSize: _titleFontSize(scale),
        fontWeight: FontWeight.w800,
        shadows: [Shadow(color: Colors.black.withValues(alpha: 0.5), blurRadius: 12)],
      ),
    );
  }

  Widget _buildMetadataLine(BuildContext context, MediaItem media) {
    final scale = _scale(context);
    final parts = [
      if (media.isMovie) t.discover.movie else if (media.isShow) t.discover.tvShow,
      if (media.rating != null) '★ ${formatRating(media.rating!)}',
      if (media.contentRating != null) formatContentRating(media.contentRating!),
      if (media.durationMs != null) formatDurationTextual(media.durationMs!),
      if (media.year != null) media.year.toString(),
    ];
    return Text(
      parts.join('  •  '),
      maxLines: 1,
      overflow: TextOverflow.ellipsis,
      style: TextStyle(
        color: Colors.white,
        fontSize: _metadataFontSize(scale),
        fontWeight: FontWeight.w700,
        letterSpacing: 0.1,
      ),
    );
  }

  double _sectionGap(double scale) => (compact ? 10 : 16) * scale;

  double _logoWidth(double scale) =>
      (compact ? TvLayoutConstants.compactHeroLogoWidth : TvLayoutConstants.heroLogoWidth) * scale;

  double _logoHeight(double scale) =>
      (compact ? TvLayoutConstants.compactHeroLogoHeight : TvLayoutConstants.heroLogoHeight) * scale;

  double _titleFontSize(double scale) => (compact ? 44 : 54) * scale;

  double _metadataFontSize(double scale) => (compact ? 16 : 18) * scale;

  double _summaryFontSize(double scale) => (compact ? 18 : 20) * scale;

  Widget _buildPrimaryAction(BuildContext context, ColorScheme colorScheme, MediaItem media) {
    final scale = _scale(context);
    final hasProgress = media.hasActiveProgress;
    final minutesLeft = hasProgress && media.durationMs != null && media.viewOffsetMs != null
        ? ((media.durationMs! - media.viewOffsetMs!) / 60000).round()
        : 0;

    return GestureDetector(
      onTap: onPrimaryAction,
      child: Container(
        padding: EdgeInsets.symmetric(horizontal: (compact ? 24 : 30) * scale, vertical: (compact ? 12 : 15) * scale),
        decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(32 * scale)),
        child: Row(
          mainAxisSize: MainAxisSize.min,
          children: [
            AppIcon(Symbols.play_arrow_rounded, fill: 1, size: (compact ? 24 : 28) * scale, color: Colors.black),
            SizedBox(width: (compact ? 10 : 12) * scale),
            Text(
              hasProgress ? t.discover.minutesLeft(minutes: minutesLeft) : t.common.play,
              style: TextStyle(color: Colors.black, fontSize: (compact ? 16 : 18) * scale, fontWeight: FontWeight.w800),
            ),
          ],
        ),
      ),
    );
  }

  String _summaryText(MediaItem media, String summary) {
    final prefix = _episodePrefix(media);
    if (prefix == null) return summary;
    return '$prefix: $summary';
  }

  String? _episodePrefix(MediaItem media) {
    if (!media.isEpisode || media.parentIndex == null || media.index == null) return null;
    return 'S${media.parentIndex}, E${media.index}';
  }
}
