import 'package:flutter/material.dart';
import 'dart:math' as math;
import '../utils/reduce_motion.dart';

/// 슬라이드 + 페이드 전환
class SlidePageRoute<T> extends PageRouteBuilder<T> {
  final Widget page;
  final AxisDirection direction;

  SlidePageRoute({
    required this.page,
    this.direction = AxisDirection.right,
  }) : super(
          pageBuilder: (context, animation, secondaryAnimation) => page,
          transitionDuration: ReduceMotion.platform()
              ? Duration.zero
              : const Duration(milliseconds: 300),
          reverseTransitionDuration: ReduceMotion.platform()
              ? Duration.zero
              : const Duration(milliseconds: 300),
          transitionsBuilder: (context, animation, secondaryAnimation, child) {
            Offset begin;
            switch (direction) {
              case AxisDirection.right:
                begin = const Offset(-1.0, 0.0);
                break;
              case AxisDirection.left:
                begin = const Offset(1.0, 0.0);
                break;
              case AxisDirection.up:
                begin = const Offset(0.0, 1.0);
                break;
              case AxisDirection.down:
                begin = const Offset(0.0, -1.0);
                break;
            }

            const end = Offset.zero;
            const curve = Curves.easeOutCubic;

            var tween = Tween(begin: begin, end: end).chain(
              CurveTween(curve: curve),
            );
            var offsetAnimation = animation.drive(tween);

            var fadeTween = Tween(begin: 0.0, end: 1.0).chain(
              CurveTween(curve: curve),
            );
            var fadeAnimation = animation.drive(fadeTween);

            return SlideTransition(
              position: offsetAnimation,
              child: FadeTransition(
                opacity: fadeAnimation,
                child: child,
              ),
            );
          },
        );
}

/// 스케일 + 페이드 전환
class ScalePageRoute<T> extends PageRouteBuilder<T> {
  final Widget page;
  final Alignment alignment;

  ScalePageRoute({
    required this.page,
    this.alignment = Alignment.center,
  }) : super(
          pageBuilder: (context, animation, secondaryAnimation) => page,
          transitionDuration: ReduceMotion.platform()
              ? Duration.zero
              : const Duration(milliseconds: 400),
          reverseTransitionDuration: ReduceMotion.platform()
              ? Duration.zero
              : const Duration(milliseconds: 400),
          transitionsBuilder: (context, animation, secondaryAnimation, child) {
            const curve = Curves.elasticOut;

            var scaleTween = Tween(begin: 0.0, end: 1.0).chain(
              CurveTween(curve: curve),
            );
            var scaleAnimation = animation.drive(scaleTween);

            var fadeTween = Tween(begin: 0.0, end: 1.0).chain(
              CurveTween(curve: Curves.easeIn),
            );
            var fadeAnimation = animation.drive(fadeTween);

            return ScaleTransition(
              scale: scaleAnimation,
              alignment: alignment,
              child: FadeTransition(
                opacity: fadeAnimation,
                child: child,
              ),
            );
          },
        );
}

/// 회전 + 스케일 전환
class RotatePageRoute<T> extends PageRouteBuilder<T> {
  final Widget page;

  RotatePageRoute({required this.page})
      : super(
          pageBuilder: (context, animation, secondaryAnimation) => page,
          transitionDuration: ReduceMotion.platform()
              ? Duration.zero
              : const Duration(milliseconds: 500),
          reverseTransitionDuration: ReduceMotion.platform()
              ? Duration.zero
              : const Duration(milliseconds: 500),
          transitionsBuilder: (context, animation, secondaryAnimation, child) {
            const curve = Curves.easeInOut;

            var rotateTween = Tween(begin: -0.5, end: 0.0).chain(
              CurveTween(curve: curve),
            );
            var rotateAnimation = animation.drive(rotateTween);

            var scaleTween = Tween(begin: 0.0, end: 1.0).chain(
              CurveTween(curve: curve),
            );
            var scaleAnimation = animation.drive(scaleTween);

            return Transform(
              alignment: Alignment.center,
              transform: Matrix4.identity()
                ..setEntry(3, 2, 0.001)
                ..rotateZ(rotateAnimation.value),
              child: Transform.scale(
                scale: scaleAnimation.value,
                child: child,
              ),
            );
          },
        );
}

/// 3D 플립 전환
class FlipPageRoute<T> extends PageRouteBuilder<T> {
  final Widget page;
  final bool horizontal;

  FlipPageRoute({
    required this.page,
    this.horizontal = true,
  }) : super(
          pageBuilder: (context, animation, secondaryAnimation) => page,
          transitionDuration: ReduceMotion.platform()
              ? Duration.zero
              : const Duration(milliseconds: 800),
          reverseTransitionDuration: ReduceMotion.platform()
              ? Duration.zero
              : const Duration(milliseconds: 800),
          transitionsBuilder: (context, animation, secondaryAnimation, child) {
            final isAnimatingForward =
                animation.status == AnimationStatus.forward;

            final flipAnimation = Tween(
              begin: 0.0,
              end: isAnimatingForward ? -math.pi : math.pi,
            ).animate(CurvedAnimation(
              parent: animation,
              curve: Curves.easeInOut,
            ));

            return AnimatedBuilder(
              animation: flipAnimation,
              builder: (context, child) {
                final isShowingFront = flipAnimation.value.abs() < math.pi / 2;

                return Transform(
                  alignment: Alignment.center,
                  transform: Matrix4.identity()
                    ..setEntry(3, 2, 0.001)
                    ..rotateY(horizontal ? flipAnimation.value : 0)
                    ..rotateX(horizontal ? 0 : flipAnimation.value),
                  child: isShowingFront
                      ? Container()
                      : Transform(
                          alignment: Alignment.center,
                          transform: Matrix4.identity()
                            ..rotateY(horizontal ? math.pi : 0)
                            ..rotateX(horizontal ? 0 : math.pi),
                          child: child,
                        ),
                );
              },
              child: child,
            );
          },
        );
}

/// 컨테이너 트랜스폼 (Material Design)
class ContainerTransformPageRoute<T> extends PageRouteBuilder<T> {
  final Widget page;
  final Widget startWidget;
  final BorderRadius? borderRadius;

  ContainerTransformPageRoute({
    required this.page,
    required this.startWidget,
    this.borderRadius,
  }) : super(
          pageBuilder: (context, animation, secondaryAnimation) => page,
          transitionDuration: ReduceMotion.platform()
              ? Duration.zero
              : const Duration(milliseconds: 500),
          reverseTransitionDuration: ReduceMotion.platform()
              ? Duration.zero
              : const Duration(milliseconds: 500),
          transitionsBuilder: (context, animation, secondaryAnimation, child) {
            return Stack(
              children: [
                // 배경 페이드
                FadeTransition(
                  opacity: animation,
                  child: Container(
                    color: Theme.of(context)
                        .colorScheme
                        .scrim
                        .withValues(alpha: 0.3),
                  ),
                ),
                // 컨테이너 확장 애니메이션
                AnimatedBuilder(
                  animation: animation,
                  builder: (context, _) {
                    final progress = animation.value;
                    final scale = 0.5 + (0.5 * progress);
                    final radius = borderRadius?.topLeft.x ?? 0;
                    final currentRadius = radius * (1 - progress);

                    return Transform.scale(
                      scale: scale,
                      child: ClipRRect(
                        borderRadius: BorderRadius.circular(currentRadius),
                        child: progress < 0.5 ? startWidget : child,
                      ),
                    );
                  },
                  child: child,
                ),
              ],
            );
          },
        );
}

/// 커스텀 Hero 애니메이션
class CustomHeroPageRoute<T> extends PageRouteBuilder<T> {
  final Widget page;
  final String heroTag;

  CustomHeroPageRoute({
    required this.page,
    required this.heroTag,
  }) : super(
          pageBuilder: (context, animation, secondaryAnimation) => page,
          transitionDuration: const Duration(milliseconds: 500),
          reverseTransitionDuration: const Duration(milliseconds: 500),
          transitionsBuilder: (context, animation, secondaryAnimation, child) {
            return FadeTransition(
              opacity: CurvedAnimation(
                parent: animation,
                curve: const Interval(0.5, 1.0),
              ),
              child: child,
            );
          },
        );
}

/// 공유 축 전환 (Material Design)
class SharedAxisPageRoute<T> extends PageRouteBuilder<T> {
  final Widget page;
  final SharedAxisTransitionType transitionType;

  SharedAxisPageRoute({
    required this.page,
    required this.transitionType,
  }) : super(
          pageBuilder: (context, animation, secondaryAnimation) => page,
          transitionDuration: ReduceMotion.platform()
              ? Duration.zero
              : const Duration(milliseconds: 300),
          reverseTransitionDuration: ReduceMotion.platform()
              ? Duration.zero
              : const Duration(milliseconds: 300),
          transitionsBuilder: (context, animation, secondaryAnimation, child) {
            late final Offset begin;
            late final Offset end;

            switch (transitionType) {
              case SharedAxisTransitionType.horizontal:
                begin = const Offset(1.0, 0.0);
                end = Offset.zero;
                break;
              case SharedAxisTransitionType.vertical:
                begin = const Offset(0.0, 1.0);
                end = Offset.zero;
                break;
              case SharedAxisTransitionType.scaled:
                begin = Offset.zero;
                end = Offset.zero;
                break;
            }

            final slideTween = Tween(begin: begin, end: end);
            final fadeTween = Tween(begin: 0.0, end: 1.0);
            final scaleTween = transitionType == SharedAxisTransitionType.scaled
                ? Tween(begin: 0.8, end: 1.0)
                : Tween(begin: 1.0, end: 1.0);

            final slideAnimation = animation.drive(slideTween);
            final fadeAnimation = animation.drive(fadeTween);
            final scaleAnimation = animation.drive(scaleTween);

            return SlideTransition(
              position: slideAnimation,
              child: FadeTransition(
                opacity: fadeAnimation,
                child: ScaleTransition(
                  scale: scaleAnimation,
                  child: child,
                ),
              ),
            );
          },
        );
}

enum SharedAxisTransitionType {
  horizontal,
  vertical,
  scaled,
}
