import 'package:particle_field/particle_field.dart';
import 'package:wonders/common_libs.dart';
import 'package:wonders/logic/data/collectible_data.dart';
import 'package:wonders/ui/common/app_backdrop.dart';
import 'package:wonders/ui/common/centered_box.dart';
import 'package:wonders/ui/common/controls/app_header.dart';
import 'package:wonders/ui/common/pop_navigator_underlay.dart';

part 'widgets/_animated_ribbon.dart';
part 'widgets/_celebration_particles.dart';

class CollectibleFoundScreen extends StatelessWidget {
  // CollectibleItem passes in a (theoretically) pre-loaded imageProvider.
  // we could check for load completion, and hold after introT, but that shouldn't be necessary in a real-world scenario.
  const CollectibleFoundScreen({required this.collectible, required this.imageProvider, Key? key}) : super(key: key);

  final CollectibleData collectible;
  final ImageProvider imageProvider;

  @override
  Widget build(BuildContext context) {
    return RepaintBoundary(
      child: _buildIntro(context).animate().swap(
            delay: $styles.times.fast * 3.5,
            builder: (_, __) => _buildDetail(context),
          ),
    );
  }

  Widget _buildIntro(BuildContext context) {
    Duration t = $styles.times.fast;
    return Stack(children: [
      Animate().custom(duration: t * 5, builder: (context, ratio, _) => _buildGradient(context, ratio, 0)),

      // icon is handled by Hero initially, then scales slowly:
      Center(
        child: FractionallySizedBox(
          widthFactor: 0.33,
          heightFactor: 0.33,
          child: Hero(
            tag: 'collectible_icon_${collectible.id}',
            child: Image(
              image: collectible.icon,
              fit: BoxFit.contain,
            ),
          ),
        ).animate().scale(begin: 1.5, end: 3, curve: Curves.easeInExpo, delay: t, duration: t * 3).fadeOut(),
      )
    ]);
  }

  Widget _buildDetail(BuildContext context) {
    Duration t = $styles.times.fast;
    return Stack(key: ValueKey('detail'), children: [
      /// Background
      AppBackdrop(
        strength: .5,
        child: Container(color: $styles.colors.greyStrong.withOpacity(.96)),
      ).animate().fadeIn(),

      /// Particles
      _CelebrationParticles(fadeMs: (t * 6).inMilliseconds),

      /// invisible close btn
      PopNavigatorUnderlay(),

      /// Content
      SafeArea(
        child: CenteredBox(
          width: $styles.sizes.maxContentWidth3,
          child: Column(
            children: [
              Gap($styles.insets.lg),
              Spacer(),
              SizedBox(
                height: context.heightPx * .35,
                child: Center(child: Hero(tag: 'collectible_image_${collectible.id}', child: _buildImage(context))),
              ),
              Gap($styles.insets.lg),
              _buildRibbon(context),
              Gap($styles.insets.sm),
              _buildTitle(context, collectible.title, $styles.text.h2, $styles.colors.offWhite, t * 1.5),
              Gap($styles.insets.xs),
              _buildTitle(
                  context, collectible.subtitle.toUpperCase(), $styles.text.title2, $styles.colors.accent1, t * 2),
              Spacer(),
              Gap($styles.insets.lg),
              _buildCollectionButton(context),
              Gap($styles.insets.lg),
              Spacer(),
            ],
          ),
        ),
      ),
      AppHeader(isTransparent: true).animate().fade(delay: t * 4, duration: t * 2),
    ]);
  }

  Widget _buildGradient(BuildContext context, double ratioIn, double ratioOut) {
    // used by both intro and detail animations to ensure they share a mid-point.
    ratioIn = Curves.easeOutExpo.transform(ratioIn);
    final double opacity = 1.0 * (ratioIn * 0.8 + ratioOut * 0.2);
    final Color light = $styles.colors.offWhite;
    final Color dark = $styles.colors.black;

    // final state is a solid fill, so optimize that case:
    if (ratioOut == 1) return Container(color: dark.withOpacity(opacity));

    return Container(
      decoration: BoxDecoration(
        gradient: RadialGradient(
          colors: [Color.lerp(light, dark, ratioOut)!.withOpacity(opacity), dark.withOpacity(opacity)],
          stops: [0.2, min(1, 0.25 + ratioIn * 0.5 + ratioOut * 0.5)],
        ),
      ),
    );
  }

  Widget _buildImage(BuildContext context) {
    Duration t = $styles.times.fast;
    // build an image with animated shadows and scaling
    return AppImage(image: imageProvider, scale: 1.0)
        .animate()
        .custom(
          duration: t * 6,
          builder: (_, ratio, child) => Container(
            padding: EdgeInsets.all($styles.insets.xxs),
            margin: EdgeInsets.symmetric(horizontal: $styles.insets.xl),
            decoration: BoxDecoration(color: $styles.colors.offWhite, boxShadow: [
              BoxShadow(
                color: $styles.colors.accent1.withOpacity(ratio * 0.75),
                blurRadius: $styles.insets.xl * 2,
              ),
              BoxShadow(
                color: $styles.colors.black.withOpacity(ratio * 0.75),
                offset: Offset(0, $styles.insets.xxs),
                blurRadius: $styles.insets.sm,
              ),
            ]),
            child: child,
          ),
        )
        .scale(begin: 0.3, duration: t * 2, curve: Curves.easeOutExpo, alignment: Alignment(0, 0.7));
  }

  Widget _buildRibbon(BuildContext context) {
    Duration t = $styles.times.fast;
    return _AnimatedRibbon($strings.collectibleFoundTitleArtifactDiscovered.toUpperCase())
        .animate()
        .scale(begin: 0.3, duration: t * 2, curve: Curves.easeOutExpo, alignment: Alignment(0, -1));
  }

  Widget _buildTitle(BuildContext context, String text, TextStyle style, Color color, Duration delay) {
    Duration t = $styles.times.fast;
    // because this is a performance-sensitive screen, we are fading in the text by adjusting color:
    return Container(
      padding: EdgeInsets.symmetric(horizontal: $styles.insets.lg),
      child: Animate().custom(
        delay: delay,
        duration: t * 2,
        builder: (_, m, __) => Text(
          text,
          maxLines: 2,
          overflow: TextOverflow.ellipsis,
          textAlign: TextAlign.center,
          style: style.copyWith(color: color.withOpacity(m)),
        ),
      ),
    );
  }

  Widget _buildCollectionButton(BuildContext context) {
    Duration t = $styles.times.med;
    return AppBtn.from(
      text: $strings.collectibleFoundButtonViewCollection,
      isSecondary: true,
      onPressed: () => _handleViewCollectionPressed(context),
    ).animate().fadeIn(delay: t).move(
          begin: Offset(0, 50),
          duration: t,
          curve: Curves.easeOutCubic,
        );
  }

  void _handleViewCollectionPressed(BuildContext context) {
    Navigator.pop(context);
    context.push(ScreenPaths.collection(collectible.id));
  }
}
