/// Created by @Haoyi on 2021/4/14

part of 'transform_animation.dart';

class AnimatedTransformContainer extends StatefulWidget {
  final Widget? child;
  final double? width;
  final double? height;
  final Color? color;
  final bool showAfterStarted;
  final bool autoPlay;
  final AnimatedBehavior completedBehavior;
  final VoidCallback? onCompleted;
  final String name;

  final List<TransformAnimation> animations = [];

  AnimatedTransformContainer.single(
      {Key? key,
      this.child,
      this.width,
      this.height,
      this.color,
      this.showAfterStarted = true,
      this.autoPlay = true,
      this.onCompleted,
      this.completedBehavior = AnimatedBehavior.show,
      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));
  }

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

  AnimatedTransformContainer.director(
      {Key? key,
      this.child,
      this.width,
      this.height,
      this.color,
      this.showAfterStarted = false,
      this.autoPlay = true,
      this.completedBehavior = AnimatedBehavior.show,
      this.onCompleted,
      this.name = ""})
      : super(key: key);

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

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

  Matrix4 _lastMatrix = Matrix4.identity();

  void _onNext() {
    // print("[${widget.name}]_onNext ${animations.isEmpty} ${animations.length} ${_completedBehavior}");
    if (animations.isEmpty) {
      // print("[${widget.name}] animations is Empty");
      _lastMatrix = _animator?.matrix ?? Matrix4.identity();
      _animatedBehavior = _completedBehavior;
      setState(() {});
      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, name: widget.name);
    });
  }

  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, name: widget.name);
      }
    }
  }

  @override
  void dispose() {
    print("[${widget.name}] animated_transform_widget dispose");
    _animator?.dispose();
    _animator = null;
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    // print("[${widget.name}] _animatedBehavior:$_animatedBehavior");
    return _animatedBehavior == AnimatedBehavior.hide
        ? SizedSpacer(width: widget.width, height: widget.height)
        : SizedBox(
            width: widget.width,
            height: widget.height,
            child: LayoutBuilder(builder: (context, constraints) {
              final animator = _animator;
              // print("[${widget.name}] showAfterStarted:${widget.showAfterStarted} animator:${animator == null}");
              return animator == null
                  ? (!widget.showAfterStarted
                      ? Container(
                          color: widget.color,
                          child: Center(
                            child: Transform(
                              transform: _lastMatrix,
                              child: widget.child,
                            ),
                          ))
                      : Container())
                  : AnimatedBuilder(
                      animation: animator.controller,
                      child: widget.child,
                      builder: (BuildContext ctx, Widget? child) {
                        return Center(
                            child: Transform(
                                transform: animator._refreshMatrix(constraints: constraints),
                                child: Opacity(
                                    opacity: (!widget.showAfterStarted || animator.isStarted) ? animator._refreshOpacity() : 0,
                                    child: Container(
                                        color: (!widget.showAfterStarted || animator.isStarted)
                                            ? animator._refreshColorOpacity(widget.color)
                                            : widget.color,
                                        child: child))));
                      });
            }),
          );
  }
}
