import 'package:auto_size_text/auto_size_text.dart';
import 'package:design/design.dart';
import 'package:guru_app/financial/iap/iap_model.dart';
import 'package:guru_app/financial/product/product_store.dart';
import 'package:guru_app/guru_app.dart';
import 'package:guru_ui/localizations/l10n/generated/app_localizations.dart';
import 'package:guru_ui/localizations/ui_strings.dart';
import 'package:guru_ui/pages/store/bundle_card.dart';
import 'package:guru_ui/pages/store/purchase_banner.dart';
import 'package:guru_ui/pages/store/purchase_card.dart';
import 'package:guru_ui/pages/store/store_controller.dart';
import 'package:guru_app/financial/product/product_model.dart';
import 'package:guru_ui/pages/store/store_design_spec.dart';
import 'package:guru_widgets/button/single_tap_widget.dart';
import 'package:guru_widgets/common/flexible_container.dart';
import 'package:guru_widgets/common/spacer.dart';
import 'package:guru_widgets/theme/guru_theme.dart';
import 'package:guru_widgets/assetbar/guru_asset_bar.dart';
import 'package:guru_popup/guru_popup.dart';
import 'package:guru_utils/widget/widget_utils.dart';
import 'package:guru_utils/router/router.dart';

enum ProductStyle { banner, card, bundle }

abstract class ProductItem {
  final Stream<bool>? visible;

  ProductItem({this.visible});
}

abstract class InseparableProductItem extends ProductItem {
  final ProductId productId;

  InseparableProductItem(this.productId, {super.visible});
}

class ComposableProductItem extends ProductItem {
  final String? name;
  final List<InseparableProductItem> items;

  ComposableProductItem(this.name, this.items);
}

class BannerItem extends InseparableProductItem {
  final PurchaseBannerStyle style;
  final String name;
  final String price;
  final String? summary;
  final String? tips;
  final VoidCallback? onPurchase;

  BannerItem(
      {required ProductId productId,
      required this.style,
      required this.price,
      required this.name,
      this.summary,
      this.tips,
      this.onPurchase,
      Key? key})
      : super(productId);
}

class BannerGroup extends ComposableProductItem {
  final bool hasDivider;
  final String? tips;

  BannerGroup(
      {required List<BannerItem> items,
      this.hasDivider = true,
      String? name,
      this.tips})
      : super(name, items);
}

enum QuantityPrefix { multiplication, plus }

class CardItem extends InseparableProductItem {
  final String illustration; // 144 x 112
  final int quantity; // 数量
  final double? extraBonus; // 0.0 ~ 1.0 的额外Bonus，如果为null将不显示
  final String? label; // 如果为null将不显示

  CardItem(
      {required ProductId productId,
      required this.illustration,
      required this.quantity,
      this.extraBonus,
      this.label})
      : super(productId);
}

class CardGroup extends ComposableProductItem {
  final PurchaseCardStyle style;
  final bool hasDivider;
  final String? tips;

  CardGroup(
      {required this.style,
      required List<CardItem> items,
      this.hasDivider = true,
      String? name,
      this.tips})
      : super(name, items);
}

class BundleItem extends InseparableProductItem {
  final String title; // 144 x 112
  final String? summary; // 数量
  final String? discountPrice;
  final String? label; // 如果为null将不显示
  final BundleCardStyle style;
  final BundleContaineBuilder builder;

  BundleItem(
      {required ProductId productId,
      required this.title,
      this.summary,
      this.discountPrice,
      required this.style,
      this.label,
      required this.builder})
      : super(productId);
}

class BundleGroup extends ComposableProductItem {
  final bool hasDivider;
  final String? tips;

  BundleGroup(
      {required List<BundleItem> items,
      this.hasDivider = true,
      String? name,
      this.tips})
      : super(name, items);
}

class StoreTheme {
  final Color? backgroundColor;
  final int cardCrossAxisCount;
  final Color? dividerColor;
  final String? tipsIcon;
  final String? closeIcon;

  static const StoreTheme defaultTheme = StoreTheme();

  final Map<PurchaseCardStyle, PurchaseCardStyleTheme> purchaseCardThemes;
  final Map<PurchaseBannerStyle, PurchaseBannerStyleTheme> purchaseBannerThemes;
  final Map<BundleCardStyle, BundleCardStyleTheme> bundleCardThemes;

  const StoreTheme(
      {this.cardCrossAxisCount = 3,
      this.backgroundColor,
      this.dividerColor,
      this.tipsIcon,
      this.closeIcon,
      this.purchaseCardThemes = const {},
      this.purchaseBannerThemes = const {},
      this.bundleCardThemes = const {}})
      : assert(cardCrossAxisCount > 0);
}

class _UIHolder {
  ThemeData? _theme;
  GuruThemeData? _guruTheme;
  StoreTheme? _storeTheme;

  late StoreDesignSpec _designSpec;
  late AppLocalizations appStrings;

  _UIHolder();

  void attach(BuildContext context) {
    _theme ??= Theme.of(context);
    _guruTheme ??= GuruTheme.of(context);
    _storeTheme ??= _guruTheme
            ?.getCustomTheme<StoreTheme>(StoreTheme.defaultTheme.runtimeType) ??
        StoreTheme.defaultTheme;
    _designSpec = StoreDesignSpec.get();
    appStrings = UIStrings.get();
  }
}

mixin _UIData {
  final _UIHolder _uiHolder = _UIHolder();

  ThemeData get theme => _uiHolder._theme ?? ThemeData();

  GuruThemeData get guruTheme => _uiHolder._guruTheme ?? GuruThemeData();

  StoreTheme get storeTheme => _uiHolder._storeTheme ?? StoreTheme.defaultTheme;

  StoreDesignSpec get designSpec => _uiHolder._designSpec;

  AppLocalizations get appStrings => _uiHolder.appStrings;
}

class StorePage extends GetWidget<StoreController> with _UIData {
  final List<ProductItem> items;
  final bool subPage;

  StorePage({super.key, required this.items, this.subPage = false});

  // @override
  // void onInit() {
  //   print('dasdasdasd');
  //   final intents = controller.initIntents(items);
  //   controller.observeIapProducts(intents);
  // }

  List<Widget> buildCardGroup(CardGroup cardGroup) {
    final cardTheme = storeTheme.purchaseCardThemes[cardGroup.style]!;
    return [
      buildDivider(cardGroup.name ?? '', tips: cardGroup.tips),
      StreamBuilder<ProductStore<IapProduct>>(
        stream: controller.observableProductStore,
        builder: (context, snapshot) {
          final store = snapshot.data;
          return Center(
            child: GridView.builder(
                padding: const EdgeInsets.all(0),
                shrinkWrap: true,
                physics: const NeverScrollableScrollPhysics(),
                gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                    crossAxisCount: storeTheme.cardCrossAxisCount,
                    childAspectRatio: designSpec.cardAspectRatio,
                    mainAxisSpacing: designSpec.cardGridMainAxisSpacing,
                    crossAxisSpacing: designSpec.cardGridCrossAxisSpacing),
                itemCount: cardGroup.items.length,
                itemBuilder: (context, index) {
                  return LayoutBuilder(builder: (context, constraint) {
                    final designSpec = PurchaseCardDesignSpec.from(
                        Size(constraint.maxWidth, constraint.maxHeight));
                    final cardItem = cardGroup.items[index] as CardItem;
                    final product = store?.getProduct(cardItem.productId);
                    return PurchaseCard(
                        model: PurchaseCardModel(
                            product: product,
                            cardItem: cardItem,
                            styleTheme: cardTheme,
                            designSpec: designSpec,
                            onTap: () async {
                              controller.handlePurchase(cardItem.productId);
                            }));
                  });
                }),
          );
        }
      )
    ];
  }

  List<Widget> buildBannerGroup(BannerGroup bannerGroup) {
    final List<Widget> items = [];
    if (bannerGroup.hasDivider) {
      items.add(buildDivider(bannerGroup.name ?? '', tips: bannerGroup.tips));
    }
    final List<Widget> banners = [];
    for (var i = 0; i < bannerGroup.items.length; i++) {
      final item = bannerGroup.items[i] as BannerItem;
      banners.add(buildPurchaseBanner(item));
    }
    items.addAll(WidgetUtils.separate(
        banners, SizedBox(height: designSpec.bundleCardBottomSpacing)));
    return items;
  }

  Widget buildPurchaseBanner(BannerItem item) {
    final store = controller.currentProductStore;
    final product = store.getProduct(item.productId);
    return PurchaseBanner(
        model: PurchaseBannerModel(
            product: product,
            bannerItem: item,
            styleTheme: storeTheme.purchaseBannerThemes[item.style]!,
            designSpec: designSpec.purchaseBannerDesignSpec,
            onTap: () async {
              controller.handlePurchase(item.productId);
            }),
        tipsKey: controller.getKey(item.name));
  }

  List<Widget> buildBundleGroup(BundleGroup bundleGroup) {
    final List<Widget> items = [];
    if (bundleGroup.hasDivider) {
      items.add(buildDivider(bundleGroup.name ?? '', tips: bundleGroup.tips));
    }
    final List<Widget> bundles = [];
    for (var i = 0; i < bundleGroup.items.length; i++) {
      final item = bundleGroup.items[i] as BundleItem;
      bundles.add(buildBundleItem(item));
    }
    items.addAll(WidgetUtils.separate(
        bundles, SizedBox(height: designSpec.bundleCardBottomSpacing)));
    return items;
  }

  Widget buildBundleItem(BundleItem item) {
    final store = controller.currentProductStore;
    final product = store.getProduct(item.productId);
    return BundleCard(
        model: BundleCardModel(
            product: product,
            bundleItem: item,
            styleTheme: storeTheme.bundleCardThemes[item.style]!,
            designSpec: designSpec.bundleCardDesignSpec,
            onTap: () async {
              controller.handlePurchase(item.productId);
            }));
  }

  List<Widget> buildItemWidget(ProductItem item) {
    final List<Widget> items = [];
    if (item is CardGroup) {
      items.addAll(buildCardGroup(item));
    }
    if (item is BannerItem) {
      items.add(buildPurchaseBanner(item));
    }
    if (item is BannerGroup) {
      items.addAll(buildBannerGroup(item));
    }
    if (item is BundleItem) {
      items.add(buildBundleItem(item));
    }
    if (item is BundleGroup) {
      items.addAll(buildBundleGroup(item));
    }
    return items;
  }

  Widget buildDivider(String name, {String? tips}) {
    final tipsIcon = guruTheme.iconScheme.tipsIcon ?? storeTheme.tipsIcon;
    return Padding(
      padding: designSpec.dividerPadding,
      child: SizedBox(
        height: designSpec.dividerHeight,
        child: Row(
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            Expanded(
                flex: 1,
                child: FlexibleContainer(
                  height: designSpec.dividerLineHeight,
                  margin: designSpec.dividerItemPadding,
                  gradient: LinearGradient(
                      begin: Alignment.centerLeft,
                      end: Alignment.centerRight,
                      colors: [
                        Colors.white.withOpacity(0),
                        Colors.white.withOpacity(0.36)
                      ]),
                )),
            Padding(
              padding: designSpec.dividerItemPadding,
              child: AutoSizeText(
                name,
                textAlign: TextAlign.center,
                maxLines: 1,
                minFontSize: 7,
                style: TextStyle(
                    fontSize: designSpec.dividerTipFontSize,
                    fontWeight: GuruTheme.fwBold,
                    color: Colors.white),
              ),
            ),
            if (tips != null)
              Padding(
                padding: EdgeInsets.only(right: designSpec.tipsSpacing),
                child: GestureDetector(
                    onTap: () {
                      GuruPopup.instance.showTipsOverlay(
                          WidgetUtils.getWidgetBoundary(controller.getKey(name),
                              offset: const Offset(0.0, 2.0)),
                          width: designSpec.tipsWidth,
                          height: designSpec.tipsMinHeight,
                          radius: Radius.circular(designSpec.tipsRadius),
                          spacing: Get.statusBarHeight / Get.pixelRatio + 4,
                          nipHeight: 8,
                          nipWidth: 18,
                          backgroundColor: Colors.black.withOpacity(0.9),
                          child: buildTipContent(designSpec, tips));
                    },
                    child: tipsIcon != null
                        ? Image.asset(tipsIcon,
                            key: controller.getKey(name),
                            width: designSpec.dividerTipSize,
                            height: designSpec.dividerTipSize)
                        : Icon(Icons.help_outline,
                            key: controller.getKey(name),
                            size: designSpec.dividerTipSize,
                            color: Colors.white)),
              ),
            Expanded(
                flex: 1,
                child: FlexibleContainer(
                  height: designSpec.dividerLineHeight,
                  margin: designSpec.dividerItemPadding,
                  gradient: LinearGradient(
                      end: Alignment.centerLeft,
                      begin: Alignment.centerRight,
                      colors: [
                        Colors.white.withOpacity(0),
                        Colors.white.withOpacity(0.36)
                      ]),
                )),
          ],
        ),
      ),
    );
  }

  Widget buildAppBar() {
    final closeIcon = storeTheme.closeIcon ?? guruTheme.iconScheme.closeIcon;
    final colorScheme = guruTheme.colorScheme;
    final appbarColor = colorScheme.primaryContentColor ?? Colors.white;
    final title = Text(
      appStrings.store,
      style: TextStyle(
          fontSize: designSpec.appBarTitleFontSize,
          color: appbarColor,
          fontWeight: FontWeight.w700),
    );
    Widget closeWidget = closeIcon != null
        ? Image.asset(closeIcon,
            width: designSpec.appBarIconSize,
            height: designSpec.appBarIconSize)
        : Icon(Icons.close,
            size: designSpec.appBarIconSize, color: appbarColor);

    return Padding(
        padding: designSpec.appbarPadding,
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            subPage
                ? TapWidget(
                  inkWell: true,
                  shape: const CircleBorder(),
                  onTap: () {
                    RouteCenter.instance.back();
                  },
                  child: SizedBox.square(
                    dimension: designSpec.appBarIconButtonSize,
                    child: Center(
                        child: closeWidget),
                  ))
                : title,
            Padding(padding: designSpec.assetsBarPadding, child: GuruAssetBar(
                key: controller.getKey("assetBar"),
                style: GuruAssetBarStyle.igc,
                balanceStream: controller.observableIgcBalance))
            
          ],
        ));
  }

  @override
  Widget build(BuildContext context) {
    _uiHolder.attach(context);
    controller.initProducts(items);

    final itemWidgets = <Widget>[];
    for (var item in items) {
      final widgets = buildItemWidget(item);
      itemWidgets.addAll(widgets);
      itemWidgets.add(SizedBox(height: designSpec.groupItemSpacing));
    }

    return SafeArea(
      bottom: false,
        child: Column(children: [
      SizedSpacer(height: designSpec.appBarTopSpacing),
      buildAppBar(),
      Expanded(
          child: SingleChildScrollView(
        padding: designSpec.srcollViewPadding,
        child: Padding(
            padding: designSpec.contentPadding,
            child: Column(children: itemWidgets)),
      ))
    ]));
  }

  Widget buildTipContent(StoreDesignSpec designSpec, String? tips) {
    return Material(
      child: Padding(
        padding: designSpec.tipsContentPadding,
        child: Text(
          tips ?? '',
          textAlign: TextAlign.center,
          style: TextStyle(
            fontSize: designSpec.tipsFontSize,
            fontWeight: GuruTheme.fwMedium,
            color: Colors.white,
            height: 1.56,
          ),
        ),
      ),
    );
  }
}
