/// Created by @Haoyi on 2021/7/16

part of 'transform_animation.dart';

class AnimatedTransformBuilder extends StatefulWidget {
  final Widget? child;
  final bool showAfterStarted;
  final bool autoPlay;
  final AnimatedBehavior completedBehavior;
  final VoidCallback? onCompleted;
  final Alignment alignment;
  final String name;
  final List<TransformAnimation> animations = [];

  AnimatedTransformBuilder.single({Key? key,
    this.child,
    this.showAfterStarted = true,
    this.autoPlay = true,
    this.onCompleted,
    VoidCallback? onAnimationCompleted,
    this.completedBehavior = AnimatedBehavior.show,
    this.alignment = Alignment.center,
    Duration delayed = const Duration(milliseconds: 0),
    Duration duration = const Duration(milliseconds: 800),
    int repeat = 0,
    Duration interval = const Duration(milliseconds: 0),
    int intervalCount = 1,
    bool reverse = false,
    bool medianPending = false,
    Curve curve = Curves.linear,
    Curve reverseCurve = Curves.linear,
    double fromOpacity = 1.0,
    double toOpacity = 1.0,
    double fromColorOpacity = 1.0,
    double toColorOpacity = 1.0,
    Offset fromTranslation = Offset.zero,
    Offset toTranslation = Offset.zero,
    double fromAngle = 0.0,
    double toAngle = 0.0,
    double? fromScale = 1.0,
    double? toScale = 1.0,
    double? fromXScale,
    double? toXScale,
    double? fromYScale,
    double? toYScale,
    this.name = ""})
      : super(key: key) {
    animations.add(TransformAnimation(
        delayed: delayed,
        duration: duration,
        repeat: repeat,
        interval: interval,
        intervalCount: intervalCount,
        reverse: reverse,
        medianPending: medianPending,
        curve: curve,
        reverseCurve: reverseCurve,
        fromOpacity: fromOpacity,
        toOpacity: toOpacity,
        fromScale: fromScale,
        toScale: toScale,
        fromXScale: fromXScale,
        toXScale: toXScale,
        fromYScale: fromYScale,
        toYScale: toYScale,
        fromAngle: fromAngle,
        toAngle: toAngle,
        fromColorOpacity: fromColorOpacity,
        toColorOpacity: toColorOpacity,
        fromTranslation: fromTranslation,
        toTranslation: toTranslation,
        onCompleted: onAnimationCompleted));
  }

  AnimatedTransformBuilder.sequentially({Key? key,
    this.child,
    this.showAfterStarted = true,
    this.autoPlay = true,
    this.onCompleted,
    this.completedBehavior = AnimatedBehavior.show,
    this.alignment = Alignment.center,
    List<TransformAnimation> animations = const <TransformAnimation>[],
    this.name = ""})
      : super(key: key) {
    this.animations.addAll(animations);
  }

  AnimatedTransformBuilder.director({Key? key,
    this.child,
    this.showAfterStarted = false,
    this.autoPlay = true,
    this.completedBehavior = AnimatedBehavior.show,
    this.alignment = Alignment.center,
    this.onCompleted,
    this.name = ""})
      : super(key: key);

  @override
  State<StatefulWidget> createState() {
    return AnimatedTransformBuilderState();
  }
}

class AnimatedTransformBuilderState extends State<AnimatedTransformBuilder>
    with TickerProviderStateMixin {
  DoubleLinkedQueue<TransformAnimation> animations = DoubleLinkedQueue();
  _Animator? _animator;
  AnimatedBehavior _animatedBehavior = AnimatedBehavior.show;
  AnimatedBehavior _completedBehavior = AnimatedBehavior.show;

  Matrix4 _lastMatrix = Matrix4.identity();

  void _onNext() {
    print("_onNext ${animations.isEmpty} ${animations.length} ${widget.name}");
    if (animations.isEmpty) {
      setState(() {
        _animatedBehavior = _completedBehavior;
      });
      widget.onCompleted?.call();
      return;
    }
    final animation = animations.removeFirst();
    setState(() {
      _lastMatrix = _animator?.matrix ?? Matrix4.identity();
      _animator?.dispose();
      _animator = _Animator.schedule(
        animation,
        vsync: this,
        widgetKey: widget.key,
        initState: AnimatorState.started,
        onCompleted: _onNext,
      );
    });
  }

  void play() {
    _onNext();
  }

  void stop({AnimatedBehavior behavior = AnimatedBehavior.show}) {
    setState(() {
      _animator?.dispose();
      _animator = null;
      animations.clear();
      _animatedBehavior = behavior;
    });
  }

  void scheduleAnimations(List<TransformAnimation> transformAnimations,
      {bool append = false, AnimatedBehavior completedBehavior = AnimatedBehavior.show}) {
    _completedBehavior = completedBehavior;
    if (append) {
      bool empty = animations.isEmpty;
      animations.addAll(transformAnimations);
      if (empty) {
        _onNext();
      }
    } else {
      // print("scheduleAnimations ${transformAnimations.length}");
      animations.clear();
      animations.addAll(transformAnimations);
      _onNext();
    }
  }

  @override
  void initState() {
    super.initState();
    animations.addAll(widget.animations);
    if (widget.autoPlay) {
      final animation = animations.isNotEmpty ? animations.removeFirst() : null;
      if (animation != null) {
        _completedBehavior = widget.completedBehavior;
        _animator = _Animator.schedule(animation,
            vsync: this, widgetKey: widget.key, onStarted: () {}, onCompleted: _onNext);
      }
    }
  }

  @override
  void dispose() {
    print("animated_transform_widget dispose ${_animator?.animation.toAngle}");
    _animator?.dispose();
    _animator = null;
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final animator = _animator;
    if (_animatedBehavior == AnimatedBehavior.hide) {
      return Opacity(opacity: 0.0, child: widget.child);
    }
    return animator == null
        ? (!widget.showAfterStarted
        ? Transform(
      transform: _lastMatrix,
      child: widget.child,
    )
        : Opacity(opacity: 0.0, child: widget.child))
        : AnimatedBuilder(
        animation: animator.controller,
        child: widget.child,
        builder: (BuildContext ctx, Widget? child) {
          return Transform(
              alignment: widget.alignment,
              transform: animator._refreshMatrix(),
              child: Opacity(
                  opacity: (!widget.showAfterStarted || animator.isStarted)
                      ? animator._refreshOpacity()
                      : 0,
                  child: child));
        });
  }
}
