import 'dart:async';
import 'dart:ui' as ui;

import 'package:design/design.dart';
import 'package:flutter/material.dart';
import 'package:guru_widgets/guru_widgets.dart';
import 'package:guru_widgets/localizations/l10n/generated/app_localizations.dart';
import 'package:guru_widgets/localizations/widgets_strings.dart';
import 'package:guru_widgets/theme/guru_theme.dart';
import 'package:guru_utils/widget/widget_utils.dart';
import 'package:rxdart/rxdart.dart';
import 'package:guru_utils/currency/currency_utils.dart';
import 'package:guru_utils/extensions/extensions.dart';

part 'guru_asset_bar.g.dart';

class GuruAssetBarStyle {
  final String name;

  const GuruAssetBarStyle.create(this.name);

  // 游戏内货币的资源条
  static const GuruAssetBarStyle igc = GuruAssetBarStyle.create("_igc");
}

class GuruAssetBarStyleTheme {
  final GuruAssetBarSizeSpec sizeSpec;
  final Decoration backgroundDecoration;
  final String assetIcon; // 60 x 60
  final String? trailingIcon; // 48 x 48
  final Color? balanceColor;

  const GuruAssetBarStyleTheme(this.assetIcon,
      {this.sizeSpec = GuruAssetBarSizeSpec.s1,
      this.backgroundDecoration = const GuruAssetBarSolidDecoration(),
      this.trailingIcon,
      this.balanceColor});
}

class GuruAssetBarTheme {
  final Map<GuruAssetBarStyle, GuruAssetBarStyleTheme> styles;

  const GuruAssetBarTheme({this.styles = const {}});
}

enum GuruAssetBarSizeSpec { s1, s2 }

@DesignSpec(width: 200, height: 60, specMode: SpecMode.nested)
abstract class GuruAssetBarS1DesignSpec implements BasicDesignSpec {
  @SpecHeight(60)
  double get assetIconSize;

  @SpecHeight(2)
  double get assetIconTopSpcing;

  @SpecHeight(56)
  double get barHeight;

  @SpecAbsoluteFontSize(24)
  double get balanceFontSize;

  @SpecEdgeInsets.symmetric(horizontal: SpecWidth(4))
  EdgeInsets get balancePadding;

  @SpecHeight(48)
  double get trailingSize;

  @SpecHorizontal(4)
  double get trailingEndSpacing;

  static GuruAssetBarS1DesignSpec create(Size size,
          {Offset offset = Offset.zero}) =>
      _GuruAssetBarS1DesignSpec.from(size, offset: offset);
}

@DesignSpec(width: 169, height: 72, specMode: SpecMode.nested)
abstract class GuruAssetBarS2DesignSpec implements BasicDesignSpec {
  @SpecWidth(56)
  double get barRightSpcing;

  @SpecHeight(72)
  double get assetIconSize;

  @SpecVertical(14)
  double get barTopSpacing;

  @SpecHorizontal(23)
  double get barStartSpacing;

  @SpecHorizontal(2)
  double get barEndSpacing;

  @SpecWidth(144)
  double get barWidth;

  @SpecHeight(44)
  double get barHeight;

  @SpecWidth(71)
  double get balanceWidth;

  @SpecHorizontal(49)
  double get balanceStartSpacing;

  @SpecAbsoluteFontSize(24)
  double get balanceFontSize;

  @SpecHeight(48)
  double get trailingSize;

  static GuruAssetBarS2DesignSpec create(Size size,
          {Offset offset = Offset.zero}) =>
      _GuruAssetBarS2DesignSpec.from(size, offset: offset);
}

class GuruAssetBar extends StatefulWidget {
  final GuruAssetBarStyle style;
  final bool enabledAnimation;
  final Stream<int> balanceStream;

  const GuruAssetBar(
      {super.key,
      required this.style,
      required this.balanceStream,
      this.enabledAnimation = true});

  @override
  State<StatefulWidget> createState() => GuruAssetBarState();
}

mixin _UIHolder on State<GuruAssetBar> {
  ThemeData? _theme;
  GuruThemeData? _guruTheme;
  late GuruAssetBarTheme _assetBarTheme;
  late dynamic _designSpec;
  late GuruAssetBarStyleTheme _styleTheme;
  late AppLocalizations appStrings;

  void attach(BuildContext context) {
    _theme = Theme.of(context);
    _guruTheme = GuruTheme.of(context);
    _assetBarTheme = _guruTheme?.assetBarTheme ?? const GuruAssetBarTheme();
    _styleTheme = _assetBarTheme.styles[widget.style]!;
    switch (_styleTheme.sizeSpec) {
      case GuruAssetBarSizeSpec.s1:
        _designSpec = GuruThemeDesignSpec.get().assetBarS1DesignSpec;
        break;
      case GuruAssetBarSizeSpec.s2:
        _designSpec = GuruThemeDesignSpec.get().assetBarS2DesignSpec;
        break;
      default:
    }
    appStrings = WidgetsStrings.get();
  }
}

class BalanceTransition {
  final Animation<int> animation;
  final AnimationStatusListener? listener;

  const BalanceTransition(this.animation, this.listener);
}

class GuruAssetBarSolidDecoration extends Decoration {
  final Color color;
  final GuruAssetBarSizeSpec sizeSpec;

  const GuruAssetBarSolidDecoration(
      {this.color = const Color(0xFFCCE6DB),
      this.sizeSpec = GuruAssetBarSizeSpec.s1});

  @override
  BoxPainter createBoxPainter([VoidCallback? onChanged]) {
    late dynamic designSpec;
    switch (sizeSpec) {
      case GuruAssetBarSizeSpec.s1:
        designSpec = GuruThemeDesignSpec.get().assetBarS1DesignSpec;
        break;
      case GuruAssetBarSizeSpec.s2:
        designSpec = GuruThemeDesignSpec.get().assetBarS2DesignSpec;
        break;
      default:
        designSpec = GuruThemeDesignSpec.get().assetBarS1DesignSpec;
    }
    return _GuruAssetBarSolidPainter(designSpec, color);
  }
}

class _GuruAssetBarSolidPainter extends BoxPainter {
  final Paint painter;
  final dynamic designSpec;

  _GuruAssetBarSolidPainter(this.designSpec, Color color)
      : painter = Paint()
          ..isAntiAlias = true
          ..style = PaintingStyle.fill
          ..color = color;

  @override
  void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) {
    final size = configuration.size!;
    final Offset center = size.center(offset);

    final boundary = Rect.fromCenter(
        center: center, width: size.width, height: designSpec.barHeight);

    final bg =
        RRect.fromRectAndRadius(boundary, Radius.circular(size.height / 2));

    canvas.drawRRect(bg, painter);
  }
}

class GuruAssetBarState extends State<GuruAssetBar>
    with SingleTickerProviderStateMixin, _UIHolder {
  final GlobalKey _assetIconKey = GlobalKey();
  StreamSubscription? _subscription;
  late AnimationController controller;
  final BehaviorSubject<Animation<int>?> balanceTransition =
      BehaviorSubject.seeded(null);

  int currentBalance = 0;

  @override
  void initState() {
    super.initState();
    controller = AnimationController(
        duration: const Duration(milliseconds: 700), vsync: this);
    _listenBalance();
  }

  // void updateBalanceTransition(BalanceTransition transition) {
  //   final latestBalanceTransition = balanceTransition.value;
  //   if (latestBalanceTransition?.listener != null) {
  //     latestBalanceTransition!.animation
  //         .removeStatusListener(latestBalanceTransition.listener!);
  //   }
  //   balanceTransition.addEx(transition);
  // }

  void _listenBalance() {
    _subscription ??= widget.balanceStream.listen((balance) {
      if (currentBalance != balance) {
        if (widget.enabledAnimation) {
          if (controller.isAnimating) {
            controller.stop();
          }
          if (balanceTransition.isClosed) {
            currentBalance = balance;
            return;
          }
          final lastBalance = currentBalance;
          currentBalance = balance;

          balanceTransition.addEx(IntTween(begin: lastBalance, end: currentBalance).animate(controller));
          controller.forward(from: 0.0);
        } else {
          if (balanceTransition.isClosed) {
            return;
          }
          currentBalance = balance;
          balanceTransition.addEx(AlwaysStoppedAnimation(balance));
        }
      }
    });
  }

  Rect getAssetIconBoundary() {
    return WidgetUtils.getWidgetBoundary(_assetIconKey);
  }

  Widget _buildBalanceText() {
    return StreamBuilder<Animation<int>?>(
        stream: balanceTransition.stream,
        builder: (context, snapshot) {
          final animation = snapshot.data ??
              AlwaysStoppedAnimation(currentBalance);
          if (animation is AlwaysStoppedAnimation) {
            return AutoSizeText(
              CurrencyUtils.toW(animation.value),
              maxLines: 1,
              minFontSize: 8,
              style: TextStyle(
                  fontWeight: GuruTheme.fwSemiBold,
                  fontSize: _designSpec.balanceFontSize,
                  color: _styleTheme.balanceColor),
            );
          } else {
            return AnimatedBuilder(
              animation: controller,
              builder: (context, child) {
                return AutoSizeText(
                  CurrencyUtils.toW(animation.value),
                  maxLines: 1,
                  minFontSize: 8,
                  style: TextStyle(
                      fontSize: _designSpec.balanceFontSize,
                      fontWeight: GuruTheme.fwSemiBold,
                      color: _styleTheme.balanceColor),
                );
              },
            );
          }
        });
  }

  Widget _buildS1Widget() {
    return SizedBox.fromSize(
      size: _designSpec.measuredSize,
      child: Stack(children: [
        Positioned.fill(
            left: 0,
            top: _designSpec.assetIconTopSpcing,
            bottom: _designSpec.assetIconTopSpcing,
            child: DecoratedBox(
              decoration: _styleTheme.backgroundDecoration,
              child: Row(
                children: [
                  SizedBox(width: _designSpec.assetIconSize),
                  Expanded(
                    flex: 1,
                    child: Padding(
                        padding: _designSpec.balancePadding,
                        child: Center(child: _buildBalanceText())),
                  ),
                  if (_styleTheme.trailingIcon != null)
                    AdaptiveImage(_styleTheme.trailingIcon!,
                        width: _designSpec.trailingSize,
                        height: _designSpec.trailingSize),
                  SizedSpacer(width: _designSpec.trailingEndSpacing)
                ],
              ),
            )),
        Positioned.directional(
            textDirection: Directionality.of(context),
            top: 0,
            start: 0,
            child: AdaptiveImage(
              _styleTheme.assetIcon,
              key: _assetIconKey,
              width: _designSpec.assetIconSize,
              height: _designSpec.assetIconSize,
            ))
      ]),
    );
  }

  Widget _buildS2Widget(BuildContext context) {
    final ImageConfiguration config = createLocalImageConfiguration(context);
    final Completer<ui.Image> completer = Completer<ui.Image>();
    final ImageStream stream =
        AssetImage(_styleTheme.assetIcon).resolve(config);
    late ImageStreamListener listener;

    listener = ImageStreamListener((ImageInfo image, bool sync) {
      completer.complete(image.image);
      stream.removeListener(listener);
    });

    stream.addListener(listener);

    return FutureBuilder(
        future: completer.future,
        builder: (BuildContext context, AsyncSnapshot<ui.Image> snapshot) {
          double assetIconWidth = _designSpec.assetIconSize;
          if (snapshot.hasData) {
            assetIconWidth = _designSpec.assetIconSize / (snapshot.data?.height ?? _designSpec.assetIconSize) * snapshot.data?.width;
          }
          final double barWidth = _styleTheme.trailingIcon != null
        ? ((_designSpec.barWidth as double) + _designSpec.trailingSize / 2)
        : _designSpec.barWidth;
          
          return FlexibleContainer(
              width: barWidth + assetIconWidth - _designSpec.barRightSpcing + _designSpec.barEndSpacing,
              height: _designSpec.measuredSize.height,
              child: Stack(
                children: [
                  Positioned.directional(
                      textDirection: Directionality.of(context),
                      top: _designSpec.barTopSpacing,
                      end: _designSpec.barEndSpacing,
                      child: Container(
                          width: barWidth,
                          height: _designSpec.barHeight,
                          decoration: _styleTheme.backgroundDecoration,
                          child: Row(
                            children: [
                              SizedBox(width: _designSpec.barRightSpcing),
                              SizedBox(
                                  width: _designSpec.balanceWidth,
                                  child: Center(child: _buildBalanceText())),
                            ],
                          ))),
                  Positioned.directional(
                      textDirection: Directionality.of(context),
                      top: 0.0,
                      start: 0.0,
                      child: AdaptiveImage(
                        _styleTheme.assetIcon,
                        key: _assetIconKey,
                        height: _designSpec.assetIconSize,
                      )),
                  if (_styleTheme.trailingIcon != null)
                    Positioned.directional(
                        textDirection: Directionality.of(context),
                        top: (_designSpec.assetIconSize -
                                _designSpec.trailingSize) /
                            2,
                        end: 0,
                        child: AdaptiveImage(_styleTheme.trailingIcon!,
                            width: _designSpec.trailingSize,
                            height: _designSpec.trailingSize))
                ],
              ));
        });
  }

  @override
  Widget build(BuildContext context) {
    attach(context);
    switch (_styleTheme.sizeSpec) {
      case GuruAssetBarSizeSpec.s1:
        return _buildS1Widget();
      case GuruAssetBarSizeSpec.s2:
        return _buildS2Widget(context);
      default:
        return _buildS1Widget();
    }
  }

  @override
  void dispose() {
    controller.dispose();
    _subscription?.cancel();
    super.dispose();
  }
}
