import 'dart:collection';

import 'package:animations/animations.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';

///页面过度动效
class FTransitions {
  FTransitions._();

  static final _cache = HashMap<String, CustomTransition>();

  static CustomTransition get fadeThrough => _findInCache(() => _FadeThrough());

  static CustomTransition get sharedAxisHorizontal => _findInCache(
        () => _SharedAxis(SharedAxisTransitionType.horizontal),
        tag: "x",
      );

  static CustomTransition get sharedAxisVertical => _findInCache(
        () => _SharedAxis(SharedAxisTransitionType.vertical),
        tag: "y",
      );

  static CustomTransition get sharedAxisScaled => _findInCache(
        () => _SharedAxis(SharedAxisTransitionType.scaled),
        tag: "z",
      );

  static CustomTransition _findInCache<T extends CustomTransition>(
    T Function() builder, {
    String? tag,
  }) {
    final key = tag != null ? '${T.toString()}_$tag' : T.toString();
    if (!_cache.containsKey(key)) {
      _cache[key] = builder();
    }
    return _cache[key]!;
  }
}

///公用过度动效轴
class _SharedAxis extends CustomTransition
    with CustomTransitionListenableMixin {
  _SharedAxis(this.transitionType);

  final SharedAxisTransitionType transitionType;

  @override
  Widget buildTransition(
    BuildContext context,
    Curve? curve,
    Alignment? alignment,
    Animation<double> animation,
    Animation<double> secondaryAnimation,
    Widget child,
  ) {
    injectAnimation(animation);
    return SharedAxisTransition(
      animation: animation,
      secondaryAnimation: secondaryAnimation,
      transitionType: transitionType,
      child: child,
    );
  }
}

///闪现过度动效
class _FadeThrough extends CustomTransition
    with CustomTransitionListenableMixin {
  @override
  Widget buildTransition(
    BuildContext context,
    Curve? curve,
    Alignment? alignment,
    Animation<double> animation,
    Animation<double> secondaryAnimation,
    Widget child,
  ) {
    injectAnimation(animation);
    return FadeThroughTransition(
      animation: animation,
      secondaryAnimation: secondaryAnimation,
      child: child,
    );
  }
}

mixin CustomTransitionListenableMixin on CustomTransition {
  final _cbMap = <int, ValueChanged<AnimationStatus>>{};

  @protected
  void injectAnimation(Animation animation) {
    animation.addStatusListener((status) {
      if (status == AnimationStatus.completed) {
        for (var cb in _cbMap.values) {
          cb(status);
        }
      }
    });
  }

  void addAnimationListener(ValueChanged<AnimationStatus> callback) {
    _cbMap[callback.hashCode] = callback;
  }

  void removeAnimationListener(ValueChanged<AnimationStatus> callback) {
    _cbMap.remove(callback.hashCode);
  }
}
