import 'dart:ui';

import 'package:design/design.dart';
import 'package:design_spec/design_spec.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:guru_widgets/appbar/guru_app_bar.dart';
import 'package:guru_widgets/assetbar/guru_asset_bar.dart';
import 'package:guru_widgets/banner/purchase_banner.dart';
import 'package:guru_widgets/button/guru_button.dart';
import 'package:guru_widgets/navigationbar/guru_navigation_bar.dart';
import 'package:guru_widgets/tabbar/guru_tab_bar.dart';
import 'package:guru_widgets/sliderbar/guru_slider_bar.dart';
import 'package:guru_widgets/tile/guru_list_tile.dart';
import 'package:guru_utils/feedback/feedback_manager.dart';
import 'package:guru_widgets/gem_overlay/guru_gem_overlay.dart';

/// Created by Haoyi on 2023/5/20
///
///
part 'guru_theme.g.dart';

typedef WidgetDecorator = DecoratedBox Function(Widget? child);

class GuruDialogTheme {
  final Color titleColor;
  final Color subtitleColor;
  final Color summaryColor;
  final Color backgroundColor;
  final Color spotlightCloseIconColor;
  final Color spotlightCloseIconBgColor;
  final WidgetDecorator? customDecorator;

  const GuruDialogTheme(
      {this.titleColor = const Color(0xFF181B36),
      this.subtitleColor = const Color(0xFF6C6D71),
      this.summaryColor = const Color(0xFF181B36),
      this.backgroundColor = Colors.white,
      this.spotlightCloseIconColor = Colors.white,
      this.spotlightCloseIconBgColor = const Color(0x33000000),
      this.customDecorator});
}

class GuruButtonDecorator {
  final WidgetDecorator active;
  final WidgetDecorator? inactive;
  final WidgetDecorator? pressed;
  final Color? contentTintColor;

  GuruButtonDecorator(
      {required this.active, this.inactive, this.pressed, this.contentTintColor = Colors.white});
}

class GuruButtonElevatedScheme {
  final Color? backgroundColor;
  final Color? contentTintColor;
  final BorderRadius? radius;
  final Color? overlayColor;
  final Color? shadowColor;
  final double? elevation;
  final GuruButtonFillType? fillType;

  const GuruButtonElevatedScheme(
      {this.backgroundColor,
      this.contentTintColor,
      this.radius,
      this.overlayColor,
      this.shadowColor,
      this.elevation,
      this.fillType});
}

class GuruButtonStyle {
  final String name;

  const GuruButtonStyle.create(this.name);

  @override
  String toString() {
    return 'StandardButtonStyle{name: $name}';
  }

  static const GuruButtonStyle positive = GuruButtonStyle.create("positive");
  static const GuruButtonStyle neutral = GuruButtonStyle.create("neutral");
  static const GuruButtonStyle negative = GuruButtonStyle.create("negative");
  static const GuruButtonStyle purchase = GuruButtonStyle.create("purchase");

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is GuruButtonStyle && runtimeType == other.runtimeType && name == other.name;

  @override
  int get hashCode => name.hashCode;
}

class GuruButtonTheme {
  final Map<GuruButtonStyle, GuruButtonDecorator> decorators;
  final GuruButtonDecorator? defaultDecorator;

  final Map<GuruButtonStyle, GuruButtonElevatedScheme> elevatedSchemes;
  final GuruButtonElevatedScheme? primaryElevatedScheme;

  const GuruButtonTheme(
      {this.decorators = const {},
      this.defaultDecorator,
      this.elevatedSchemes = const {},
      this.primaryElevatedScheme});
}

class GuruListTileTheme {
  final Color? backgroundColor;
  final Color? primaryContentColor;
  final Color? secondaryContentColor;
  final Color? dividerColor;

  const GuruListTileTheme(
      {this.backgroundColor,
      this.primaryContentColor,
      this.secondaryContentColor,
      this.dividerColor});
}

class GuruOverlayColorScheme {
  final Color? backgroundColor;

  final Color? expressiveColor;

  final Color? textColor;

  final Color? dividerColor;

  const GuruOverlayColorScheme(
      {this.backgroundColor, this.expressiveColor, this.textColor, this.dividerColor});
}

class GuruTheme extends StatelessWidget {
  static const FontWeight fwThin = FontWeight.w100; // 纤细体
  static const FontWeight fwExtraLight = FontWeight.w200; // 加细体
  static const FontWeight fwLight = FontWeight.w300; // 细体
  static const FontWeight fwRegular = FontWeight.w400; // 常规体
  static const FontWeight fwMedium = FontWeight.w500; // 中黑体
  static const FontWeight fwSemiBold = FontWeight.w600; // 中粗体
  static const FontWeight fwBold = FontWeight.w700; // 粗体
  static const FontWeight fwExtraBold = FontWeight.w800; // 加粗体
  static const FontWeight fwBlack = FontWeight.w900; // 黑体

  final Widget child;
  final GuruThemeData guruTheme;
  final SystemAdaptation? adaptation;

  GuruTheme({super.key, required this.guruTheme, required this.child, this.adaptation}) {
    /// FIXME: 如果这里嵌套使用将会出现问题
    if (adaptation != null) {
      SystemAdaptation.defaultSystemAdaptation = adaptation;
    }
  }

  static GuruThemeData of(BuildContext context) {
    final _InheritedGuruTheme? inheritedTheme =
        context.dependOnInheritedWidgetOfExactType<_InheritedGuruTheme>();
    return inheritedTheme?.themeData ?? GuruThemeData.fallback();
  }

  @override
  Widget build(BuildContext context) {
    return _InheritedGuruTheme(guruTheme, child: child);
  }
}

class LottieAsset {
  final String url;
  final String? package;
  final Duration duration;

  LottieAsset(this.url, this.duration, {this.package});
}

class GuruIconScheme {
  final String? closeIcon;

  // 对话框的关闭按钮，如果为空默认使用closeIcon
  final String? dialogCloseIcon;

  // 返回按钮
  final String? backIcon;

  // Switch On
  final String? switchOnIcon;

  // Switch Off
  final String? switchOffIcon;

  final String? entranceIcon;

  final String? checkedIcon;

  final String? uncheckedIcon;

  final String? tipsIcon;

  final String? adsVideoIcon;

  final String? leftArrowIcon;

  final String? rightArrowIcon;

  const GuruIconScheme(
      {this.closeIcon,
      this.dialogCloseIcon,
      this.backIcon,
      this.switchOnIcon,
      this.switchOffIcon,
      this.entranceIcon,
      this.checkedIcon,
      this.uncheckedIcon,
      this.tipsIcon,
      this.adsVideoIcon,
      this.leftArrowIcon,
      this.rightArrowIcon});
}

class GuruColorScheme {
  final Color? primaryColor;

  final Color? secondaryColor;

  final Color? primaryContentColor;

  final Color? secondaryContentColor;

  final Color? backgroundColor;

  final Color? containerColor;

  final Color? dividerColor;

  final GuruOverlayColorScheme? overlayColors;

  const GuruColorScheme(
      {this.primaryColor,
      this.secondaryColor,
      this.primaryContentColor,
      this.secondaryContentColor,
      this.backgroundColor,
      this.containerColor,
      this.dividerColor,
      this.overlayColors});
}

class GuruAppBarTheme {
  final bool hasStatusBar;
  final Color? backgroundColor;

  const GuruAppBarTheme({this.backgroundColor, this.hasStatusBar = false});
}

class GuruTabBarTheme {
  final Color? backgroundColor;
  final Color? selectedColor;
  final Color? selectedBackgroundColor;
  final Color? unSelctedColor;
  final Color? unSelectedBackgroundColor;
  final Decoration? indicator;

  const GuruTabBarTheme(
      {this.backgroundColor,
      this.selectedColor,
      this.selectedBackgroundColor,
      this.unSelctedColor,
      this.unSelectedBackgroundColor,
      this.indicator});
}

class GuruNavigationBarTheme {
  final Color? backgroundColor;
  final Color? selectedColor;
  final Color? selectedBackgroundColor;
  final Color? unSelctedColor;
  final Color? navigationBarTopDividerColor;
  final double? navigationBarTopDividerHeight;
  final BottomNavigationBarType? type;

  const GuruNavigationBarTheme(
      {this.backgroundColor,
      this.selectedColor,
      this.selectedBackgroundColor,
      this.unSelctedColor,
      this.navigationBarTopDividerColor,
      this.navigationBarTopDividerHeight,
      this.type});
}

class GuruSliderBarTheme {
  final String? anchorIcon;
  final double? anchorOffset;
  final double? horizontalOffset;
  final Decoration? background;
  final List<GuruSliderBarItem>? items;
  final Duration? duration;
  final Curve? curve;

  const GuruSliderBarTheme(
      {this.anchorIcon,
      this.anchorOffset,
      this.horizontalOffset,
      this.background,
      this.items,
      this.duration,
      this.curve});
}

@DesignSpec(width: 750, height: 1624)
abstract class GuruThemeDesignSpec extends BasicDesignSpec {
  @NestedSpec(750, 128, consistentHeight: true)
  GuruListTileDesignSpec get pageListTileDesignSpec;

  @NestedSpec(750, 94, consistentHeight: true)
  GuruAppBarDesignSpec get appBarDesignSpec;

  @NestedSpec(750, 1624, consistentHeight: true)
  GuruTabBarDesignSpec get tabBarDesignSpec;

  @NestedSpec(750, 49, consistentHeight: true)
  GuruNavigationBarDesignSpec get navigationBarDesignSpec;

  @NestedSpec(750, 120, consistentHeight: true)
  GuruSliderBarDesignSpec get sliderBarDesignSpec;

  @NestedSpec(200, 60, consistentHeight: true)
  GuruAssetBarS1DesignSpec get assetBarS1DesignSpec;

  @NestedSpec(169, 72, consistentHeight: true)
  GuruAssetBarS2DesignSpec get assetBarS2DesignSpec;

  @NestedSpec(750, 200, consistentHeight: true)
  PurchaseBannerDesignSpec get purchaseBannerDesignSpec;

  static GuruThemeDesignSpec get() => _GuruThemeDesignSpec.get();
}

class GuruCustomTheme {
  final Map<Type, dynamic> themeData;

  const GuruCustomTheme.empty() : themeData = const {};

  GuruCustomTheme({List<Object> themes = const []})
      : themeData = {for (var theme in themes) theme.runtimeType: theme};
}

class GuruThemeData {
  final GuruDialogTheme dialogTheme;
  final GuruButtonTheme buttonTheme;
  final GuruListTileTheme listTileTheme;
  final GuruIconScheme iconScheme;
  final GuruColorScheme colorScheme;
  final GuruAppBarTheme appBarTheme;
  final GuruTabBarTheme tabBarTheme;
  final GuruNavigationBarTheme navigationBarTheme;
  final GuruAssetBarTheme assetBarTheme;
  final GuruSliderBarTheme sliderBarTheme;
  final GuruGemsOverlayTheme gemsOverlayTheme;
  final GuruCustomTheme customTheme;

  final FeedbackCapabilities feedbackCapabilities;

  GuruThemeDesignSpec get designSpec => GuruThemeDesignSpec.get();

  T? getCustomTheme<T>(Type type) {
    return customTheme.themeData[type] as T?;
  }

  GuruThemeData(
      {this.iconScheme = const GuruIconScheme(),
      this.dialogTheme = const GuruDialogTheme(),
      this.buttonTheme = const GuruButtonTheme(),
      this.listTileTheme = const GuruListTileTheme(),
      this.colorScheme = const GuruColorScheme(),
      this.appBarTheme = const GuruAppBarTheme(),
      this.tabBarTheme = const GuruTabBarTheme(),
      this.navigationBarTheme = const GuruNavigationBarTheme(),
      this.assetBarTheme = const GuruAssetBarTheme(),
      this.sliderBarTheme = const GuruSliderBarTheme(),
      this.gemsOverlayTheme = const GuruGemsOverlayTheme(),
      this.customTheme = const GuruCustomTheme.empty(),
      this.feedbackCapabilities = FeedbackCapabilities.sound});

  static GuruThemeData fallback() {
    return GuruThemeData();
  }
}

class _InheritedGuruTheme extends InheritedWidget {
  final GuruThemeData? themeData;

  const _InheritedGuruTheme(this.themeData, {required Widget child}) : super(child: child);

  @override
  bool updateShouldNotify(covariant _InheritedGuruTheme oldGuruTheme) {
    return themeData != oldGuruTheme.themeData;
  }
}
