import 'dart:math';
import 'dart:ui';

import 'package:design/design.dart';
import 'package:flame/extensions.dart';
import 'package:flutter/animation.dart';
import 'package:guru_utils/svg/svg_parser.dart';
import 'package:guru_utils/log/log.dart';
import 'package:guru_utils/visual_feast/engine/visual_feast_engine.dart';
import 'package:guru_utils/visual_feast/visual_feast_animation.dart';
import 'package:guru_widgets/assetbar/guru_asset_bar.dart';
import 'package:guru_widgets/overlay/guru_asset.dart';
import 'package:guru_widgets/theme/guru_theme.dart';


class AssetModel {
  final SvgParser parser;
  final int fps;
  final int frames;
  final int delayedFrames;

  AssetModel(this.parser, this.fps, this.frames, this.delayedFrames);

  Duration get duration => Duration(milliseconds: ((1 / fps) * frames * 1000).toInt());

  Duration get delayed => Duration(milliseconds: ((1 / fps) * delayedFrames * 1000).toInt());
}

class Asset {
  final VisualFeastSprite sprite;
  PathMetric pathMetric;
  final transaction = Vector2(0, 0);
  final latestTransaction = Vector2(0, 0);

  final Rect rect;
  final Offset center;

  final Duration duration;
  final Duration delayed;
  double scale = 0.0;
  double scaleStartPercent = -1;

  late void Function(Canvas) renderCallbacks;

  Asset(this.sprite, this.rect, this.pathMetric, this.duration, this.delayed) : center = rect.center {
    renderCallbacks = (canvas) {};
  }

  BaseVisualFeastAnimation start({VoidCallback? onStarted, VoidCallback? onComplete}) {
    return VisualFeastAnimation(
        duration: duration,
        delayed: delayed,
        curve: const Cubic(1, 0, 0.7, 0.7),
        onStarted: () {
          renderCallbacks = _render;
          scale = 0.0;
        },
        onUpdate: (value, percent, elapsed) {
          final tangent = pathMetric.getTangentForOffset(pathMetric.length * value);
          if (tangent != null) {
            transaction.setValues(tangent.position.dx, tangent.position.dy);
          }
          if (scaleStartPercent == -1) {
            if (transaction.y < latestTransaction.y) {
              // final shift = transaction.y - latestTransaction.y;
              // Log.d("shift:$shift $percent");
              scaleStartPercent = percent;
            }
            scale = min(percent * 6, 1.3);
            latestTransaction.setFrom(transaction);
          } else {
            scale = 1.3 - (0.3 * ((percent - scaleStartPercent) / (1 - scaleStartPercent)));
          }
        },
        onCompleted: () {
          renderCallbacks = (_) {};
          onComplete?.call();
        });
  }

  void _render(Canvas canvas) {
    canvas.save();
    canvas.translate(transaction.x, transaction.y);
    canvas.save();
    canvas.translate(center.dx, center.dy);
    canvas.scale(scale, scale);
    canvas.translate(-center.dx, -center.dy);
    sprite.renderRect(canvas, rect);
    canvas.restore();
    canvas.restore();
  }

  void render(Canvas canvas) {
    renderCallbacks(canvas);
  }
}

class AssetsReward extends VisualFeastRender {
  static const path1 =
      "M37.1820557,82.9721758 C37.1820557,91.0223101 36.3053084,95.4060466 34.5518139,96.1233852 C31.921572,97.1993933 20.3245964,95.4060466 0,0";
  static const path2 =
      "M41.246975,73.168547 C41.5657922,78.508735 41.0477143,81.5773506 39.6927412,82.3743936 C37.6602815,83.5699581 26.4219753,80.102821 0,0";
  static const path3 =
      "M41.8447573,84.7655226 C42.2432788,91.7795009 41.6056444,95.525603 39.9318541,96.0038288 C37.4211686,96.7211675 19.3681448,96.0038288 0,0";
  static const path4 =
      "M38.3776202,85.4828613 C39.3340718,90.9824579 38.7761417,94.1307778 36.7038299,94.9278208 C33.5953623,96.1233852 18.1725803,93.7322563 0,0";
  static const path5 =
      "M40.0514105,77.1139098 C40.0514105,90.0260063 39.0949589,96.7211675 37.1820557,97.1993933 C34.312701,97.916732 24.8677415,94.9278208 0,0";
  static const path6 =
      "M36.8233864,74.0054421 C37.3813165,90.8230493 36.7038299,99.4709658 34.7909268,99.9491916 C31.921572,100.66653 22.1179431,95.0473772 0,0";
  static const path7 =
      "M34.4322574,82.3743936 C34.8307789,92.0983181 34.312701,97.7174712 32.8780236,99.2318529 C30.7260075,101.503425 19.1290319,95.0473772 0,0";
  static const path8 =
      "M33.8344752,78.7877001 C34.3924053,83.7293667 33.8344752,86.3994607 32.1606849,86.7979822 C29.6499994,87.3957644 20.0854835,86.0806435 0,0";
  static const path9 =
      "M36.3451606,81.8961678 C36.3451606,88.7507375 35.5082654,92.4171353 33.8344752,92.8953611 C31.3237897,93.6126998 2.51068544,90.3846757 0,0";

  static final gemModels = [
    AssetModel(SvgParser.create(svgPath: path1), 50, 56, 6),
    AssetModel(SvgParser.create(svgPath: path2), 50, 58, 2),
    AssetModel(SvgParser.create(svgPath: path3), 50, 57, 18),
    AssetModel(SvgParser.create(svgPath: path4), 50, 57, 13),
    AssetModel(SvgParser.create(svgPath: path5), 50, 54, 10),
    AssetModel(SvgParser.create(svgPath: path6), 50, 57, 8),
    AssetModel(SvgParser.create(svgPath: path7), 50, 54, 0),
    AssetModel(SvgParser.create(svgPath: path8), 50, 57, 4),
    AssetModel(SvgParser.create(svgPath: path9), 50, 57, 14),
  ];

  final GlobalKey key;

  @override
  int get orderInLayer => 5;

  final AssetOverlayTheme theme;

  final List<Asset> assets = [];

  Rect boundary = Rect.zero;
  final GuruAssetBarSizeSpec barSize;

  VoidCallback? onFirstAssetComplete;
  VoidCallback? onAllAssetsComplete;

  AssetsReward(this.key, this.barSize, {
    this.onFirstAssetComplete,
    this.onAllAssetsComplete,
  }) : theme = GuruTheme.of(Get.context!).getCustomTheme<AssetOverlayTheme>(AssetOverlayTheme.defaultTheme.runtimeType) ?? AssetOverlayTheme.defaultTheme; 

  void initPathReward() {
    RenderObject? widgetRenderBox = key.currentContext?.findRenderObject();
    Offset widgetOffset = (widgetRenderBox as RenderBox).localToGlobal(Offset.zero);
    Size widgetsize = widgetRenderBox.size;
    Rect dst = Rect.fromLTWH(widgetOffset.dx, widgetOffset.dy, widgetsize.height, widgetsize.height);
    final size = Get.size;
    Rect src;
    Rect renderRect;
    if (barSize == GuruAssetBarSizeSpec.s1) {
      final GuruAssetBarS1DesignSpec designSpec = GuruThemeDesignSpec.get().assetBarS1DesignSpec;
      renderRect = Rect.fromLTWH(0, 0, designSpec.assetIconSize, designSpec.assetIconSize);
      src = Rect.fromCenter(center: Offset(size.width / 2, size.height / 2 + designSpec.assetIconSize * 2), width: widgetsize.height, height: widgetsize.height);
    } else {
      final GuruAssetBarS2DesignSpec designSpec = GuruThemeDesignSpec.get().assetBarS2DesignSpec;
      renderRect = Rect.fromLTWH(0, 0, designSpec.assetIconSize, designSpec.assetIconSize);
      src = Rect.fromCenter(center: Offset(size.width / 2, size.height / 2 + designSpec.assetIconSize * 2), width: widgetsize.height, height: widgetsize.height);
    }
    final gemSprite = getSprite("asset");
    // final radian = (2 * pi) / gemModels.length;

    for (var idx = 0; idx < theme.assetCount; ++idx) {
      final modalIndex = idx % 9;
      final gemModel = gemModels[modalIndex];
      final parser = gemModel.parser;
      final region = Rect.fromLTRB(dst.left, dst.top, src.right, src.bottom);
      final path = parser.path;
      final matrix4 = Matrix4.compose(Vector3(dst.left, dst.top, 0), Quaternion.identity(),
          Vector3(region.width / 42.0, region.height / 100.0, 1));
      final newPath = path.transform(matrix4.storage);
      PathMetrics pathMetrics = newPath.computeMetrics();
      assets.add(Asset(gemSprite, renderRect, pathMetrics.first, gemModel.duration, gemModel.delayed));
    }
    Log.d("initPathReward");
  }

  @override
  void onStart() {
    super.onStart();
    Log.d("onStart gems_reward!");
    final List<BaseVisualFeastAnimation> animations = [];
    for (var idx = 0; idx < assets.length; ++idx) {
      final gem = assets[idx];
      animations.add(gem.start(
          onComplete: (idx == 0)
              ? () {
                  onFirstAssetComplete?.call();
                }
              : null));
    }
    final animation = VisualFeastAnimationSet.together(animations, onCompleted: () {
      onAllAssetsComplete?.call();
      Log.d("gems_reward completed!");
    });
    attachAnimation(animation, end: false);
    Log.d("onStart gems_reward! ${animation.id}");
  }

  @override
  void onAttach() {
    super.onAttach();
    initPathReward();
  }

  @override
  void onDetach() {
    assets.clear();
    onFirstAssetComplete = null;
    engine.detachRenders([this]);
    super.onDetach();
  }

  @override
  void onFrameUpdate(double dt) {}

  @override
  void onRender(Canvas canvas) {
    super.onRender(canvas);
    for (var asset in assets) {
      asset.render(canvas);
    }
  }

  @override
  String get renderId => "GemsReward";
}
