import 'dart:async';

import 'package:design/design.dart';
import 'package:guru_widgets/button/guru_button.dart';
import 'package:guru_widgets/guru_widgets.dart';
import 'package:guru_widgets/image/adaptive_image.dart';
import 'package:guru_widgets/theme/guru_theme.dart';
import 'package:guru_utils/router/router.dart';
import 'package:guru_utils/feedback/feedback_manager.dart';

/// Created by Haoyi on 2023/5/19

part 'guru_dialog.g.dart';

@DesignSpec(width: 750, height: 1624)
abstract class GuruDialogContainerDesignSpec implements BasicDesignSpec {
  @SpecHeight(48)
  double get minHeight;

  @SpecRadius.circular(SpecHeight(40))
  BorderRadius get defaultDialogRadius;

  @NestedAspectSpec(654 / 672, 0.872, widthUpperLimit: 400)
  GuruDialogDesignSpec get dialogSpec;

  @NestedAspectSpec(654 / 672, 0.872, widthUpperLimit: 400)
  GuruSpotlightDialogDesignSpec get spotlightDialogSpec;

  @NestedAspectWidthSpec(654, 1.60244)
  GuruExtendDialogDesignSpec get extendDialogSpec;

  @NestedAspectWidthSpec(654, 0.57492355)
  GuruConfirmDialogDesignSpec get confirmDialogSpec;

  @NestedAspectWidthSpec(590, 0.55668359)
  GuruAlertDialogDesignSpec get alertDialogSpec;

  static GuruDialogContainerDesignSpec get() => _GuruDialogContainerDesignSpec.get();
}

@DesignSpec(width: 654, height: 672, specMode: SpecMode.nested)
abstract class GuruDialogDesignSpec implements BasicDesignSpec {
  @SpecEdgeInsets.only(start: SpecHorizontal(20), top: SpecVertical(28))
  EdgeInsetsDirectional get closeButtonMargin;

  @SpecEdgeInsets.symmetric(vertical: SpecVertical(64))
  EdgeInsets get contentPadding;

  @SpecHeight(72)
  double get closeButtonSize;

  @SpecHeight(48)
  double get closeIconSize;

  @SpecEdgeInsets.only(
      top: SpecVertical(16),
      bottom: SpecVertical(8),
      start: SpecHorizontal(96),
      end: SpecHorizontal(96))
  EdgeInsets get titlePadding;

  @SpecAbsoluteFontSize(36)
  double get titleFontSize;

  @SpecEdgeInsets.only(top: SpecVertical(16), start: SpecHorizontal(96), end: SpecHorizontal(96))
  EdgeInsets get subtitlePadding;

  @SpecAbsoluteFontSize(28)
  double get subtitleFontSize;

  @SpecEdgeInsets.only(top: SpecVertical(24), bottom: SpecVertical(24), start: SpecHorizontal(63), end: SpecHorizontal(63))
  EdgeInsets get illustrationPadding;

  @SpecAspectHeightSize(320, 1.65)
  Size get illustrationSize;

  @SpecEdgeInsets.only(bottom: SpecVertical(24), start: SpecHorizontal(56), end: SpecHorizontal(56))
  EdgeInsets get summaryPadding;

  @SpecAbsoluteFontSize(28)
  double get summaryFontSize;

  @SpecEdgeInsets.only(top: SpecVertical(24), bottom: SpecVertical(16))
  EdgeInsets get primaryButtonPadding;

  @SpecAspectHeightSize(96, 5.64583333)
  Size get primaryButtonSize;

  @SpecEdgeInsets.only(top: SpecVertical(28), start: SpecHorizontal(56), end: SpecHorizontal(56))
  EdgeInsets get secondaryButtonPadding;

  @SpecAbsoluteFontSize(32)
  double get secondaryButtonFontSize;

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

@DesignSpec(width: 654, height: 672, specMode: SpecMode.nested)
abstract class GuruSpotlightDialogDesignSpec implements BasicDesignSpec {
  @SpecEdgeInsets.only(start: SpecHorizontal(20), top: SpecVertical(28))
  EdgeInsetsDirectional get closeButtonMargin;

  @SpecEdgeInsets.only(top: SpecVertical(32), bottom: SpecVertical(64))
  EdgeInsets get contentPadding;

  @SpecHeight(72)
  double get closeButtonSize;

  @SpecHeight(48)
  double get closeIconSize;

  @SpecEdgeInsets.only(
      top: SpecVertical(0),
      bottom: SpecVertical(24),
      start: SpecHorizontal(56),
      end: SpecHorizontal(56))
  EdgeInsets get titlePadding;

  @SpecAbsoluteFontSize(36)
  double get titleFontSize;

  @SpecEdgeInsets.only(bottom: SpecVertical(24), start: SpecHorizontal(56), end: SpecHorizontal(56))
  EdgeInsets get subtitlePadding;

  @SpecAbsoluteFontSize(28)
  double get subtitleFontSize;

  @SpecAspectWidthSize(654, 0.667)
  Size get illustrationSize;

  @SpecEdgeInsets.only(bottom: SpecVertical(48), start: SpecHorizontal(56), end: SpecHorizontal(56))
  EdgeInsets get summaryPadding;

  @SpecAbsoluteFontSize(28)
  double get summaryFontSize;

  @SpecHeight(120)
  double get scrollAbleContentMaxHeight;

  @SpecEdgeInsets.only(bottom: SpecVertical(16))
  EdgeInsets get primaryButtonPadding;

  @SpecAspectHeightSize(96, 5.64583333)
  Size get primaryButtonSize;

  @SpecEdgeInsets.only(top: SpecVertical(28), start: SpecHorizontal(56), end: SpecHorizontal(56))
  EdgeInsets get secondaryButtonPadding;

  @SpecAbsoluteFontSize(32)
  double get secondaryButtonFontSize;

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

@DesignSpec(width: 654, height: 1048, specMode: SpecMode.nested)
abstract class GuruExtendDialogDesignSpec implements BasicDesignSpec {
  @SpecEdgeInsets.only(start: SpecHorizontal(20), top: SpecVertical(28))
  EdgeInsetsDirectional get closeButtonMargin;

  @SpecHeight(72)
  double get closeButtonSize;

  @SpecHeight(48)
  double get closeIconSize;

  @SpecAspectWidthSize(654, 1.217)
  Size get illustrationSize;

  @SpecEdgeInsets.only(
      start: SpecHorizontal(56),
      end: SpecHorizontal(56),
      top: SpecVertical(83),
      bottom: SpecVertical(80))
  EdgeInsets get contentPadding;

  @SpecEdgeInsets.only(start: SpecHorizontal(24), end: SpecHorizontal(24), bottom: SpecVertical(14))
  EdgeInsets get titlePadding;

  @SpecAbsoluteFontSize(36)
  double get titleFontSize;

  @SpecEdgeInsets.only(bottom: SpecVertical(24))
  EdgeInsets get subtitlePadding;

  @SpecAbsoluteFontSize(28)
  double get subtitleFontSize;

  @SpecEdgeInsets.only(bottom: SpecVertical(64))
  EdgeInsets get summaryPadding;

  @SpecAbsoluteFontSize(28)
  double get summaryFontSize;

  @SpecEdgeInsets.only(bottom: SpecVertical(16))
  EdgeInsets get primaryButtonPadding;

  @SpecAspectHeightSize(96, 5.64583333)
  Size get primaryButtonSize;

  @SpecEdgeInsets.only(top: SpecVertical(28), start: SpecHorizontal(56), end: SpecHorizontal(56))
  EdgeInsets get secondaryButtonPadding;

  @SpecAbsoluteFontSize(32)
  double get secondaryButtonFontSize;

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

@DesignSpec(width: 654, height: 376, specMode: SpecMode.nested)
abstract class GuruConfirmDialogDesignSpec implements BasicDesignSpec {
  @SpecEdgeInsets.symmetric(horizontal: SpecHorizontal(40), vertical: SpecHorizontal(64))
  EdgeInsets get contentPadding;

  @SpecEdgeInsets.only(
      start: SpecHorizontal(40),
      end: SpecHorizontal(40),
      top: SpecVertical(64),
      bottom: SpecVertical(48))
  EdgeInsets get noTitleContentPadding;

  @SpecEdgeInsets.only(start: SpecHorizontal(56), end: SpecHorizontal(56), bottom: SpecVertical(8))
  EdgeInsets get titlePadding;

  @SpecAbsoluteFontSize(36)
  double get titleFontSize;

  @SpecEdgeInsets.only(
      start: SpecHorizontal(16),
      end: SpecHorizontal(16),
      top: SpecVertical(16),
      bottom: SpecVertical(56))
  EdgeInsets get summaryPadding;

  @SpecEdgeInsets.only(
      start: SpecHorizontal(16),
      end: SpecHorizontal(16),
      top: SpecVertical(16),
      bottom: SpecVertical(40))
  EdgeInsets get noTitlesummaryPadding;

  @SpecAbsoluteFontSize(32)
  double get noTitleSummaryFontSize;

  @SpecAbsoluteFontSize(28)
  double get summaryFontSize;

  @SpecHeight(88)
  double get summaryMinHeight;

  @SpecHeight(96)
  double get noTitleSummaryMinHeight;

  @SpecAspectHeightSize(96, 5.64583333)
  Size get adButtonSize;

  @SpecEdgeInsets.only(top: SpecVertical(44), start: SpecHorizontal(56), end: SpecHorizontal(56))
  EdgeInsets get secondaryButtonPadding;

  @SpecAbsoluteFontSize(32)
  double get secondaryButtonFontSize;

  @SpecAspectHeightSize(96, 2.83333333)
  Size get buttonSize;

  @SpecHorizontal(29)
  double get buttonSpacing;

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

@DesignSpec(width: 590, height: 328, specMode: SpecMode.nested)
abstract class GuruAlertDialogDesignSpec implements BasicDesignSpec {
  @SpecEdgeInsets.symmetric(horizontal: SpecHorizontal(56), vertical: SpecHorizontal(64))
  EdgeInsets get contentPadding;

  @SpecEdgeInsets.only(bottom: SpecVertical(16))
  EdgeInsets get titlePadding;

  @SpecAbsoluteFontSize(36)
  double get titleFontSize;

  @SpecEdgeInsets.symmetric(horizontal: SpecHorizontal(56), vertical: SpecVertical(64))
  EdgeInsets get summaryPadding;

  @SpecAbsoluteFontSize(32)
  double get noTitleSummaryFontSize;

  @SpecAbsoluteFontSize(28)
  double get summaryFontSize;

  @SpecHeight(88)
  double get summaryMinHeight;

  @SpecHeight(96)
  double get noTitleSummaryMinHeight;

  @SpecHeight(104)
  double get buttonHeight;

  @SpecHeight(1)
  double get dividerSize;

  @SpecAbsoluteFontSize(32)
  double get buttonFontSize;

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

class DialogResult {
  final bool close;
  final dynamic result;

  DialogResult(this.close, this.result);
}

enum AlertResult { positive, negative, ignore }

// 这里返回的值代表点击完按钮后是否通过RouteCenter关闭dialog
typedef DialogButtonCallback = FutureOr<DialogResult> Function();

typedef DialogConstraintBuilder = BoxConstraints Function();

enum DialogContainerHeightConstraint { min, standard }

class GuruDialogContainer extends StatelessWidget {
  final bool clip;
  final Widget? child;
  final Color? backgroundColor;
  final DialogConstraintBuilder constraintBuilder;

  const GuruDialogContainer(
      {Key? key, this.child, this.backgroundColor, this.clip = false, required this.constraintBuilder})
      : super(key: key);

  Widget _defaultDialogDecoratedContainer(
      GuruThemeData guruTheme, GuruDialogContainerDesignSpec designSpec,
      {Widget? child}) {
    final decoratedWidget = DecoratedBox(
      decoration: BoxDecoration(
          color: backgroundColor ?? guruTheme.dialogTheme.backgroundColor,
          borderRadius: designSpec.defaultDialogRadius),
      child: child,
    );

    return clip
        ? ClipRRect(borderRadius: designSpec.defaultDialogRadius, child: decoratedWidget)
        : decoratedWidget;
  }

  Widget _inflateDialogDecoratedContainer(
      GuruThemeData guruTheme, GuruDialogContainerDesignSpec designSpec,
      {Widget? child}) {
    return guruTheme.dialogTheme.customDecorator?.call(child) ??
        _defaultDialogDecoratedContainer(guruTheme, designSpec, child: child);
  }

  @override
  Widget build(BuildContext context) {
    final GuruThemeData guruTheme = GuruTheme.of(context);
    final designSpec = GuruDialogContainerDesignSpec.get();

    return Center(
      child: ConstrainedBox(
        constraints: constraintBuilder.call(),
        child: _inflateDialogDecoratedContainer(guruTheme, designSpec, child: child),
      ),
    );
  }
}

class GuruStandardDialog extends StatefulWidget {
  final bool closable;
  final VoidCallback? onClosed;
  final DialogButtonCallback? onPrimaryButtonPressed;
  final DialogButtonCallback? onSecondaryButtonPressed;
  final String? title;
  final String? subtitle;
  final String? summary;
  final Widget? illustration;
  final GuruWidgetBuilder<GuruDialogDesignSpec>? illustrationBuilder;
  final GuruWidgetBuilder<Size>? overridePrimaryButtonBuilder;
  final Widget? primaryButtonChild;
  final String? secondaryButtonText;

  final String? primaryButtonAction;
  final String? primaryButtonLeading;
  final String? primaryButtonTrailing;
  final String? primaryButtonInfo;
  final String? primaryButtonSummary;
  final GuruButtonStyle? primaryButtonStyle;

  final List<PositionedBuilder<GuruDialogDesignSpec>> positionedBuilders;

  const GuruStandardDialog(
      {super.key,
      this.closable = true,
      this.onClosed,
      this.onPrimaryButtonPressed,
      this.onSecondaryButtonPressed,
      this.title,
      this.subtitle,
      this.summary,
      this.illustration,
      this.illustrationBuilder,
      this.overridePrimaryButtonBuilder,
      this.primaryButtonChild,
      this.primaryButtonAction,
      this.primaryButtonLeading,
      this.primaryButtonTrailing,
      this.primaryButtonInfo,
      this.primaryButtonSummary,
      this.primaryButtonStyle,
      this.secondaryButtonText,
      this.positionedBuilders = const []});

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

typedef PositionedBuilder<T> = Positioned Function(BuildContext, T);

typedef GuruWidgetBuilder<T> = Widget Function(BuildContext, T);

class _GuruStandardDialogState extends State<GuruStandardDialog> {
  late GuruDialogContainerDesignSpec designSpec;
  late GuruDialogDesignSpec dialogSpec;
  late GuruThemeData guruTheme;

  @override
  void initState() {
    super.initState();
    designSpec = GuruDialogContainerDesignSpec.get();
    dialogSpec = designSpec.dialogSpec;
  }

  Widget _buildTitle(String title) {
    return Padding(
        padding: dialogSpec.titlePadding,
        child: AutoSizeText(
          title,
          maxLines: 2,
          textAlign: TextAlign.center,
          style: TextStyle(
              fontSize: dialogSpec.titleFontSize,
              fontWeight: GuruTheme.fwBold,
              color: guruTheme.dialogTheme.titleColor),
        ));
  }

  Widget _buildSubtitle(String subtitle) {
    return Padding(
        padding: dialogSpec.subtitlePadding,
        child: AutoSizeText(
          subtitle,
          maxLines: 1,
          textAlign: TextAlign.center,
          style: TextStyle(
              fontSize: dialogSpec.subtitleFontSize,
              fontWeight: GuruTheme.fwMedium,
              color: guruTheme.dialogTheme.subtitleColor),
        ));
  }

  Widget _buildIllustration() {
    return Padding(
        padding: dialogSpec.illustrationPadding,
        child: SizedBox(
            width: dialogSpec.illustrationSize.width,
            height: dialogSpec.illustrationSize.height,
            child: widget.illustrationBuilder != null
                ? widget.illustrationBuilder!(context, dialogSpec)
                : widget.illustration));
  }

  Widget _buildSummary(String summary) {
    return Padding(
        padding: dialogSpec.summaryPadding,
        child: Text(
          summary,
          textAlign: TextAlign.center,
          maxLines: 5,
          strutStyle: const StrutStyle(height: 1.55),
          style: TextStyle(
              fontSize: dialogSpec.summaryFontSize,
              fontWeight: GuruTheme.fwMedium,
              color: guruTheme.dialogTheme.summaryColor),
        ));
  }

  Widget _buildPrimaryButton() {
    return Padding(
      padding: dialogSpec.primaryButtonPadding,
      child: widget.overridePrimaryButtonBuilder != null
          ? SizedBox(
              width: dialogSpec.primaryButtonSize.width,
              height: dialogSpec.primaryButtonSize.height,
              child:
                  widget.overridePrimaryButtonBuilder!.call(context, dialogSpec.primaryButtonSize),
            )
          : GuruButton(
              size: dialogSpec.primaryButtonSize,
              action: widget.primaryButtonAction,
              leading: widget.primaryButtonLeading,
              trailing: widget.primaryButtonTrailing,
              info: widget.primaryButtonInfo,
              summary: widget.primaryButtonSummary,
              style: widget.primaryButtonStyle,
              onPressed: () async {
                final result = await widget.onPrimaryButtonPressed?.call();
                if (result?.close == true) {
                  RouteCenter.instance.back(result: result?.result);
                }
              },
              child: widget.primaryButtonChild,
            ),
    );
  }

  Widget _buildSecondaryButton(String text) {
    final themeData = Theme.of(context);
    return GestureDetector(
      onTap: () async {
        final result = await widget.onSecondaryButtonPressed?.call();
        if (guruTheme.feedbackCapabilities.canPerform()) {
          FeedbackManager.instance.perform(FeedbackOccasion.clickButton);
        }
        if (result?.close == true) {
          RouteCenter.instance.back(result: result?.result);
        }
      },
      child: Padding(
          padding: dialogSpec.secondaryButtonPadding,
          child: Text(
            text,
            style: TextStyle(
                fontSize: dialogSpec.secondaryButtonFontSize,
                fontWeight: GuruTheme.fwSemiBold,
                color: themeData.primaryColor),
          )),
    );
  }

  List<Widget> buildItems() {
    final result = <Widget>[];

    final title = widget.title;
    if (title != null) {
      result.add(_buildTitle(title));
    }

    final scrollableItems = <Widget>[];

    final subtitle = widget.subtitle;
    if (subtitle != null) {
      scrollableItems.add(_buildSubtitle(subtitle));
    }

    scrollableItems.add(_buildIllustration());

    final summary = widget.summary;
    if (summary != null) {
      scrollableItems.add(_buildSummary(summary));
    }

    if (scrollableItems.length == 1) {
      result.add(scrollableItems[0]);
    } else {
      double height = MediaQuery.of(context).size.height;
      result.add(ConstrainedBox(
        constraints: BoxConstraints(
            minHeight: dialogSpec.illustrationSize.height,
            maxHeight: height * 0.5),
        child: SingleChildScrollView(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: scrollableItems,
          ),
        ),
      ));
    }

    result.add(_buildPrimaryButton());

    final secondaryButtonText = widget.secondaryButtonText;
    if (secondaryButtonText != null) {
      result.add(_buildSecondaryButton(secondaryButtonText));
    }
    return result;
  }

  @override
  Widget build(BuildContext context) {
    final td = Directionality.of(context);
    guruTheme = GuruTheme.of(context);
    final stackItems = <Widget>[
      Padding(
        padding: dialogSpec.contentPadding,
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: buildItems(),
        ),
      )
    ];
    if (widget.closable) {
      final closeIcon = guruTheme.iconScheme.closeIcon;
      stackItems.add(Positioned.directional(
          textDirection: td,
          top: dialogSpec.closeButtonMargin.top,
          start: dialogSpec.closeButtonMargin.start,
          child: TapWidget(
              inkWell: true,
              shape: const CircleBorder(),
              onTap: () {
                widget.onClosed?.call();
                RouteCenter.instance.back();
              },
              child: SizedBox(
                width: dialogSpec.closeButtonSize,
                height: dialogSpec.closeButtonSize,
                child: Center(
                    child: (closeIcon != null)
                        ? Image.asset(closeIcon,
                            fit: BoxFit.contain,
                            width: dialogSpec.closeIconSize,
                            height: dialogSpec.closeIconSize)
                        : Icon(Icons.close, size: dialogSpec.closeIconSize)),
              ))));
    }

    final layers =
        widget.positionedBuilders.map((builder) => builder(context, dialogSpec)).toList();
    return GuruDialogContainer(
      constraintBuilder: () {
        return BoxConstraints(
            maxWidth: dialogSpec.measuredSize.width,
            minWidth: dialogSpec.measuredSize.width,
            minHeight: dialogSpec.measuredSize.height);
      },
      child: Stack(
        fit: StackFit.loose,
        alignment: Alignment.center,
        children: [...layers, ...stackItems],
      ),
    );
  }
}

class GuruSpotlightDialog extends StatefulWidget {
  final bool closable;
  final VoidCallback? onClosed;
  final DialogButtonCallback? onPrimaryButtonPressed;
  final DialogButtonCallback? onSecondaryButtonPressed;
  final String? title;
  final String? subtitle;
  final String? summary;
  final Widget illustration;
  final Widget? primaryButtonChild;
  final String? secondaryButtonText;

  final String? primaryButtonAction;
  final String? primaryButtonLeading;
  final String? primaryButtonTrailing;
  final String? primaryButtonInfo;
  final String? primaryButtonSummary;
  final GuruButtonStyle? primaryButtonStyle;

  final GuruWidgetBuilder<Size>? overridePrimaryButtonBuilder;

  final List<PositionedBuilder<GuruSpotlightDialogDesignSpec>> positionedBuilders;

  const GuruSpotlightDialog(
      {super.key,
      this.closable = true,
      this.onClosed,
      this.onPrimaryButtonPressed,
      this.onSecondaryButtonPressed,
      this.title,
      this.subtitle,
      this.summary,
      required this.illustration,
      this.primaryButtonChild,
      this.primaryButtonAction,
      this.primaryButtonLeading,
      this.primaryButtonTrailing,
      this.primaryButtonInfo,
      this.primaryButtonSummary,
      this.primaryButtonStyle,
      this.secondaryButtonText,
      this.overridePrimaryButtonBuilder,
      this.positionedBuilders = const []});

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

class _GuruSpotlightDialogState extends State<GuruSpotlightDialog> {
  late GuruDialogContainerDesignSpec designSpec;
  late GuruSpotlightDialogDesignSpec dialogSpec;
  late GuruThemeData guruTheme;

  @override
  void initState() {
    super.initState();
    designSpec = GuruDialogContainerDesignSpec.get();
    dialogSpec = designSpec.spotlightDialogSpec;
  }

  Widget _buildIllustration() {
    return SizedBox(
      width: dialogSpec.illustrationSize.width,
      height: dialogSpec.illustrationSize.height,
      child: widget.illustration);
  }

  Widget _buildTitle(String title) {
    return Padding(
        padding: dialogSpec.titlePadding,
        child: AutoSizeText(
          title,
          maxLines: 2,
          textAlign: TextAlign.center,
          style: TextStyle(
              fontSize: dialogSpec.titleFontSize,
              fontWeight: GuruTheme.fwBold,
              color: guruTheme.dialogTheme.titleColor),
        ));
  }

  Widget _buildSubtitle(String subtitle) {
    return Padding(
        padding: dialogSpec.subtitlePadding,
        child: AutoSizeText(
          subtitle,
          maxLines: 1,
          textAlign: TextAlign.center,
          style: TextStyle(
              fontSize: dialogSpec.subtitleFontSize,
              fontWeight: GuruTheme.fwMedium,
              color: guruTheme.dialogTheme.subtitleColor),
        ));
  }

  Widget _buildSummary(String summary) {
    return Padding(
        padding: dialogSpec.summaryPadding,
        child: Text(
          summary,
          textAlign: TextAlign.center,
          maxLines: 5,
          strutStyle: const StrutStyle(height: 1.5),
          style: TextStyle(
              fontSize: dialogSpec.summaryFontSize,
              fontWeight: GuruTheme.fwMedium,
              color: guruTheme.dialogTheme.summaryColor),
        ));
  }

  Widget _buildPrimaryButton() {
    return Padding(
      padding: dialogSpec.primaryButtonPadding,
      child: widget.overridePrimaryButtonBuilder != null
        ? SizedBox(
          width: dialogSpec.primaryButtonSize.width,
          height: dialogSpec.primaryButtonSize.height,
          child: widget.overridePrimaryButtonBuilder!.call(context, dialogSpec.primaryButtonSize),
        ) : GuruButton(
        size: dialogSpec.primaryButtonSize,
        action: widget.primaryButtonAction,
        leading: widget.primaryButtonLeading,
        trailing: widget.primaryButtonTrailing,
        info: widget.primaryButtonInfo,
        summary: widget.primaryButtonSummary,
        style: widget.primaryButtonStyle,
        child: widget.primaryButtonChild,
        onPressed: () async {
          final result = await widget.onPrimaryButtonPressed?.call();
          if (result?.close == true) {
            RouteCenter.instance.back(result: result?.result);
          }
        },
      ),
    );
  }

  Widget _buildSecondaryButton(String text) {
    final themeData = Theme.of(context);
    return GestureDetector(
      onTap: () async {
        final result = await widget.onSecondaryButtonPressed?.call();
        if (guruTheme.feedbackCapabilities.canPerform()) {
          FeedbackManager.instance.perform(FeedbackOccasion.clickButton);
        }
        if (result?.close == true) {
          RouteCenter.instance.back(result: result?.result);
        }
      },
      child: Padding(
          padding: dialogSpec.secondaryButtonPadding,
          child: Text(
            text,
            style: TextStyle(
                fontSize: dialogSpec.secondaryButtonFontSize,
                fontWeight: GuruTheme.fwSemiBold,
                color: themeData.primaryColor),
          )),
    );
  }

  List<Widget> buildItems() {
    final result = <Widget>[];
    final scrollableItems = <Widget>[];

    final title = widget.title;
    if (title != null) {
      scrollableItems.add(_buildTitle(title));
    }

    final subtitle = widget.subtitle;
    if (subtitle != null) {
      scrollableItems.add(_buildSubtitle(subtitle));
    }

    final summary = widget.summary;
    if (summary != null) {
      scrollableItems.add(_buildSummary(summary));
    }

    if (scrollableItems.length == 1) {
      result.add(scrollableItems[0]);
    } else {
      double height = MediaQuery.of(context).size.height;
      result.add(ConstrainedBox(
        constraints: BoxConstraints(
            minHeight: dialogSpec.scrollAbleContentMaxHeight,
            maxHeight: height * 0.27),
        child: SingleChildScrollView(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: scrollableItems,
          ),
        ),
      ));
    }

    result.add(_buildPrimaryButton());

    final secondaryButtonText = widget.secondaryButtonText;
    if (secondaryButtonText != null) {
      result.add(_buildSecondaryButton(secondaryButtonText));
    }
    return result;
  }

  @override
  Widget build(BuildContext context) {
    final td = Directionality.of(context);
    guruTheme = GuruTheme.of(context);
    final stackItems = <Widget>[
      Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          _buildIllustration(),
          FlexibleContainer(
            width: dialogSpec.measuredSize.width,
            padding: dialogSpec.contentPadding,
            color: guruTheme.dialogTheme.backgroundColor,
            child: Column(children: buildItems()))
        ],
      )
    ];
    if (widget.closable) {
      final closeIcon = guruTheme.iconScheme.dialogCloseIcon;
      stackItems.add(Positioned.directional(
          textDirection: td,
          top: dialogSpec.closeButtonMargin.top,
          start: dialogSpec.closeButtonMargin.start,
          child: TapWidget(
              inkWell: true,
              shape: const CircleBorder(),
              materialColor: guruTheme.dialogTheme.spotlightCloseIconBgColor,
              onTap: () {
                widget.onClosed?.call();
                RouteCenter.instance.back();
              },
              child: SizedBox(
                width: dialogSpec.closeButtonSize,
                height: dialogSpec.closeButtonSize,
                child: Center(
                    child: Image(image: closeIcon != null
                            ? AssetImage(closeIcon)
                            : const AssetImage("assets/images/ic_close.png",
                                package: "guru_widgets"),
                            fit: BoxFit.contain,
                            width: dialogSpec.closeIconSize,
                            height: dialogSpec.closeIconSize,
                            color: guruTheme.dialogTheme.spotlightCloseIconColor)),
              ))));
    }

    final layers =
        widget.positionedBuilders.map((builder) => builder(context, dialogSpec)).toList();
    return GuruDialogContainer(
      constraintBuilder: () {
        return BoxConstraints(
            maxWidth: dialogSpec.measuredSize.width,
            minWidth: dialogSpec.measuredSize.width,
            minHeight: dialogSpec.measuredSize.height);
      },
      backgroundColor: Colors.transparent,
      clip: true,
      child: Stack(
        fit: StackFit.loose,
        alignment: Alignment.center,
        children: [...layers, ...stackItems],
      ),
    );
  }
}

class GuruExtendDialog extends StatefulWidget {
  final bool closable;
  final VoidCallback? onClosed;
  final DialogButtonCallback? onPrimaryButtonPressed;

  // final DialogButtonCallback? onSecondaryButtonPressed;
  final String? title;
  final Color? titleColor;

  // final String? subtitle;
  final String? summary;
  final Color? summaryColor;
  final Widget illustration;
  final BoxDecoration? contentBackground;
  final Widget? primaryButtonChild;

  // final String? secondaryButtonText;

  final String? primaryButtonAction;
  final String? primaryButtonLeading;
  final String? primaryButtonTrailing;
  final String? primaryButtonInfo;
  final String? primaryButtonSummary;

  final GuruWidgetBuilder<Size>? overridePrimaryButtonBuilder;

  final List<PositionedBuilder<GuruExtendDialogDesignSpec>> positionedBuilders;

  const GuruExtendDialog(
      {super.key,
      this.closable = true,
      this.onClosed,
      this.onPrimaryButtonPressed,
      // this.onSecondaryButtonPressed,
      this.title,
      this.titleColor,
      // this.subtitle,
      this.summary,
      this.summaryColor,
      required this.illustration,
      this.contentBackground,
      this.primaryButtonChild,
      this.primaryButtonAction,
      this.primaryButtonLeading,
      this.primaryButtonTrailing,
      this.primaryButtonInfo,
      this.primaryButtonSummary,
      // this.secondaryButtonText,
      this.overridePrimaryButtonBuilder,
      this.positionedBuilders = const []});

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

class _GuruExtendDialogState extends State<GuruExtendDialog> {
  late GuruDialogContainerDesignSpec designSpec;
  late GuruExtendDialogDesignSpec dialogSpec;
  late GuruThemeData guruTheme;

  @override
  void initState() {
    super.initState();
    designSpec = GuruDialogContainerDesignSpec.get();
    dialogSpec = designSpec.extendDialogSpec;
  }

  Widget _buildTitle(String title) {
    return Padding(
        padding: dialogSpec.titlePadding,
        child: AutoSizeText(
          title,
          maxLines: 2,
          textAlign: TextAlign.center,
          style: TextStyle(
              fontSize: dialogSpec.titleFontSize,
              fontWeight: GuruTheme.fwBold,
              color: widget.titleColor ?? guruTheme.dialogTheme.titleColor),
        ));
  }

  // Widget _buildSubtitle(String subtitle) {
  //   return Padding(
  //       padding: dialogSpec.subtitlePadding,
  //       child: AutoSizeText(
  //         subtitle,
  //         maxLines: 1,
  //         textAlign: TextAlign.center,
  //         style: TextStyle(
  //             fontSize: dialogSpec.subtitleFontSize,
  //             fontWeight: GuruTheme.fwMedium,
  //             color: guruTheme.dialogTheme.subtitleColor),
  //       ));
  // }

  Widget _buildSummary(String summary) {
    return Padding(
        padding: dialogSpec.summaryPadding,
        child: Text(
          summary,
          textAlign: TextAlign.center,
          maxLines: 5,
          strutStyle: const StrutStyle(height: 1.55),
          style: TextStyle(
              fontSize: dialogSpec.summaryFontSize,
              fontWeight: GuruTheme.fwMedium,
              color: widget.summaryColor ?? guruTheme.dialogTheme.summaryColor),
        ));
  }

  Widget _buildPrimaryButton() {
    return Padding(
      padding: dialogSpec.primaryButtonPadding,
      child: widget.overridePrimaryButtonBuilder != null
        ? SizedBox(
          width: dialogSpec.primaryButtonSize.width,
          height: dialogSpec.primaryButtonSize.height,
          child: widget.overridePrimaryButtonBuilder!.call(context, dialogSpec.primaryButtonSize),
        ) : GuruButton(
        size: dialogSpec.primaryButtonSize,
        action: widget.primaryButtonAction,
        leading: widget.primaryButtonLeading,
        trailing: widget.primaryButtonTrailing,
        info: widget.primaryButtonInfo,
        summary: widget.primaryButtonSummary,
        child: widget.primaryButtonChild,
        onPressed: () async {
          final result = await widget.onPrimaryButtonPressed?.call();
          if (result?.close == true) {
            RouteCenter.instance.back(result: result?.result);
          }
        },
      ),
    );
  }

  // Widget _buildSecondaryButton(String text) {
  //   final themeData = Theme.of(context);
  //   return GestureDetector(
  //     onTap: () async {
  //       final result = await widget.onSecondaryButtonPressed?.call();
  //       if (result?.close == true) {
  //         RouteCenter.instance.back(result: result?.result);
  //       }
  //     },
  //     child: Padding(
  //         padding: dialogSpec.secondaryButtonPadding,
  //         child: Text(
  //           text,
  //           style: TextStyle(
  //               fontSize: dialogSpec.secondaryButtonFontSize,
  //               fontWeight: GuruTheme.fwSemiBold,
  //               color: themeData.primaryColor),
  //         )),
  //   );
  // }

  List<Widget> buildItems() {
    final result = <Widget>[];

    final title = widget.title;
    if (title != null) {
      result.add(_buildTitle(title));
    }

    // final subtitle = widget.subtitle;
    // if (subtitle != null) {
    //   result.add(_buildSubtitle(subtitle));
    // }

    final summary = widget.summary;
    if (summary != null) {
      result.add(_buildSummary(summary));
    }

    result.add(_buildPrimaryButton());

    // final secondaryButtonText = widget.secondaryButtonText;
    // if (secondaryButtonText != null) {
    //   result.add(_buildSecondaryButton(secondaryButtonText));
    // }
    return result;
  }

  @override
  Widget build(BuildContext context) {
    final td = Directionality.of(context);
    guruTheme = GuruTheme.of(context);
    final stackItems = <Widget>[
      Positioned(
          top: 0,
          left: 0,
          right: 0,
          child: SizedBox(
              width: dialogSpec.illustrationSize.width,
              height: dialogSpec.illustrationSize.height,
              child: widget.illustration)),
      Positioned(
          bottom: 0,
          left: 0,
          right: 0,
          child: Container(
            decoration: widget.contentBackground,
            child: Padding(
              padding: dialogSpec.contentPadding,
              child: Column(
                mainAxisSize: MainAxisSize.min,
                children: buildItems(),
              ),
            ),
          ))
    ];
    if (widget.closable) {
      final closeIcon = guruTheme.iconScheme.dialogCloseIcon;
      stackItems.add(Positioned.directional(
          textDirection: td,
          top: dialogSpec.closeButtonMargin.top,
          start: dialogSpec.closeButtonMargin.start,
          child: TapWidget(
              inkWell: true,
              shape: const CircleBorder(),
              materialColor: guruTheme.dialogTheme.spotlightCloseIconBgColor,
              onTap: () {
                widget.onClosed?.call();
                RouteCenter.instance.back();
              },
              child: SizedBox(
                width: dialogSpec.closeButtonSize,
                height: dialogSpec.closeButtonSize,
                child: Center(
                    child: (closeIcon != null)
                        ? Image.asset(closeIcon,
                            fit: BoxFit.contain,
                            width: dialogSpec.closeIconSize,
                            height: dialogSpec.closeIconSize,
                            color: guruTheme.dialogTheme.spotlightCloseIconColor)
                        : Icon(Icons.close, size: dialogSpec.closeIconSize, color: guruTheme.dialogTheme.spotlightCloseIconColor)),
              ))));
    }

    final layers =
        widget.positionedBuilders.map((builder) => builder(context, dialogSpec)).toList();
    return GuruDialogContainer(
      constraintBuilder: () {
        double height = MediaQuery.of(context).size.height;
        if (dialogSpec.measuredSize.height < height * 0.8) {
          height = dialogSpec.measuredSize.height;
        } else {
          height = height * 0.8;
        }
        return BoxConstraints(
            maxWidth: dialogSpec.measuredSize.width,
            minWidth: dialogSpec.measuredSize.width,
            minHeight: dialogSpec.measuredSize.height,
            maxHeight: height);
      },
      clip: true,
      backgroundColor: Colors.transparent,
      child: Stack(
        fit: StackFit.loose,
        alignment: Alignment.center,
        children: [...layers, ...stackItems],
      ),
    );
  }
}

class GuruConfirmDialog extends StatelessWidget {
  final String? title;
  final String summary;
  final String negativeButtonText;
  final String positiveButtonText;
  final GuruButtonStyle? negativeButtonStyle;
  final GuruButtonStyle? positiveButtonStyle;
  final String? positiveButtonLeading;
  final String? positiveButtonTrailing;
  final String? positiveButtonInfo;
  final String? positiveButtonSummary;

  final DialogButtonCallback? onPositiveButtonPressed;
  final DialogButtonCallback? onNegativeButtonPressed;


  const GuruConfirmDialog(
      {super.key,
      this.title,
      required this.summary,
      required this.negativeButtonText,
      required this.positiveButtonText,
      this.negativeButtonStyle = GuruButtonStyle.negative,
      this.positiveButtonStyle = GuruButtonStyle.positive,
      this.positiveButtonLeading,
      this.positiveButtonTrailing,
      this.positiveButtonInfo,
      this.positiveButtonSummary,
      this.onPositiveButtonPressed,
      this.onNegativeButtonPressed});

  @override
  Widget build(BuildContext context) {
    final designSpec = GuruDialogContainerDesignSpec.get();
    final dialogSpec = designSpec.confirmDialogSpec;
    final guruTheme = GuruTheme.of(context);

    return GuruDialogContainer(
        constraintBuilder: () => BoxConstraints(
            minWidth: dialogSpec.measuredSize.width,
            maxWidth: dialogSpec.measuredSize.width,
            minHeight: dialogSpec.measuredSize.height),
        child: Padding(
            padding: title != null ? dialogSpec.contentPadding : dialogSpec.noTitleContentPadding,
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                if (title != null)
                  Padding(
                      padding: dialogSpec.titlePadding,
                      child: AutoSizeText(
                        title!,
                        maxLines: 2,
                        textAlign: TextAlign.center,
                        style: TextStyle(
                            fontSize: dialogSpec.titleFontSize,
                            fontWeight: GuruTheme.fwBold,
                            height: 1.25,
                            color: guruTheme.dialogTheme.titleColor),
                      )),
                Padding(
                    padding: positiveButtonLeading != null ? dialogSpec.summaryPadding : dialogSpec.noTitlesummaryPadding,
                    child: ConstrainedBox(
                      constraints: BoxConstraints(
                          minHeight: title != null
                              ? dialogSpec.summaryMinHeight
                              : dialogSpec.noTitleSummaryMinHeight),
                      child: Text(
                        summary,
                        textAlign: TextAlign.center,
                        maxLines: 7,
                        strutStyle: StrutStyle(height: title != null ? 1.7 : 1.5),
                        style: TextStyle(
                            fontSize: title != null
                                ? dialogSpec.summaryFontSize
                                : dialogSpec.noTitleSummaryFontSize,
                            fontWeight: GuruTheme.fwMedium,
                            color: guruTheme.dialogTheme.summaryColor),
                      ),
                    )),
                positiveButtonLeading != null ? Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    GuruButton(
                        action: positiveButtonText,
                        leading: positiveButtonLeading,
                        trailing: positiveButtonTrailing,
                        sizeSpec: GuruButtonSizeSpec.s2,
                        info: positiveButtonInfo,
                        summary: positiveButtonSummary,
                        size: dialogSpec.adButtonSize,
                        fillType: GuruButtonFillType.solid),
                    GestureDetector(
                      onTap: () async {
                        if (guruTheme.feedbackCapabilities.canPerform()) {
                          FeedbackManager.instance.perform(FeedbackOccasion.clickButton);
                        }
                        onPositiveButtonPressed?.call();
                        RouteCenter.instance.back(result: AlertResult.positive);
                      },
                      child: Padding(
                          padding: dialogSpec.secondaryButtonPadding,
                          child: Text(
                            negativeButtonText,
                            style: TextStyle(
                                fontSize: dialogSpec.secondaryButtonFontSize,
                                fontWeight: GuruTheme.fwSemiBold,
                                color: guruTheme.colorScheme.primaryColor),
                          )),
                    )
                  ]
                ) : Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    GuruButton(
                        action: negativeButtonText,
                        size: dialogSpec.buttonSize,
                        sizeSpec: GuruButtonSizeSpec.s2,
                        fillType: GuruButtonFillType.outline,
                        style: negativeButtonStyle,
                        onPressed: onNegativeButtonPressed),
                    SizedSpacer(width: dialogSpec.buttonSpacing),
                    GuruButton(
                        action: positiveButtonText,
                        leading: positiveButtonLeading,
                        trailing: positiveButtonTrailing,
                        sizeSpec: GuruButtonSizeSpec.s2,
                        info: positiveButtonInfo,
                        summary: positiveButtonSummary,
                        size: dialogSpec.buttonSize,
                        style: positiveButtonStyle,
                        fillType: GuruButtonFillType.solid,
                        onPressed: onPositiveButtonPressed,),
                  ],
                )
              ],
            )));
  }
}

class GuruAlertDialog extends StatelessWidget {
  final String? title;
  final String summary;
  final String negativeButtonText;
  final String positiveButtonText;
  final Color? negativeColor;
  final Color? positiveColor;

  const GuruAlertDialog(
      {super.key,
      this.title,
      required this.summary,
      required this.negativeButtonText,
      required this.positiveButtonText,
      this.negativeColor,
      this.positiveColor});

  @override
  Widget build(BuildContext context) {
    final designSpec = GuruDialogContainerDesignSpec.get();
    final dialogSpec = designSpec.alertDialogSpec;
    final guruTheme = GuruTheme.of(context);

    return GuruDialogContainer(
        constraintBuilder: () => BoxConstraints(
            minWidth: dialogSpec.measuredSize.width,
            maxWidth: dialogSpec.measuredSize.width,
            minHeight: dialogSpec.measuredSize.height),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Padding(
                padding: dialogSpec.contentPadding,
                child: Column(children: [
                  if (title != null)
                    Padding(
                        padding: dialogSpec.titlePadding,
                        child: AutoSizeText(
                          title!,
                          maxLines: 2,
                          textAlign: TextAlign.center,
                          style: TextStyle(
                              fontSize: dialogSpec.titleFontSize,
                              fontWeight: GuruTheme.fwBold,
                              color: guruTheme.dialogTheme.titleColor),
                        )),
                  ConstrainedBox(
                    constraints: BoxConstraints(
                        minHeight: title != null
                            ? dialogSpec.summaryMinHeight
                            : dialogSpec.noTitleSummaryMinHeight),
                    child: Text(
                      summary,
                      textAlign: TextAlign.center,
                      maxLines: 5,
                      strutStyle: StrutStyle(height: title != null ? 1.7 : 1.8),
                      style: TextStyle(
                          fontSize: title != null
                              ? dialogSpec.summaryFontSize
                              : dialogSpec.noTitleSummaryFontSize,
                          fontWeight: GuruTheme.fwMedium,
                          color: guruTheme.dialogTheme.summaryColor),
                    ),
                  )
                ])),
            HorizontalDivider(height: dialogSpec.dividerSize),
            SizedBox(
              height: dialogSpec.buttonHeight,
              child: Row(
                mainAxisAlignment: MainAxisAlignment.center,
                crossAxisAlignment: CrossAxisAlignment.stretch,
                children: [
                  Expanded(
                    flex: 1,
                    child: TapWidget(
                        inkWell: true,
                        onTap: () {
                          if (guruTheme.feedbackCapabilities.canPerform()) {
                            FeedbackManager.instance.perform(FeedbackOccasion.clickButton);
                          }
                          RouteCenter.instance.back(result: AlertResult.positive);
                        },
                        child: Center(
                          child: Text(negativeButtonText,
                              textAlign: TextAlign.center,
                              style: TextStyle(
                                  fontSize: dialogSpec.buttonFontSize,
                                  fontWeight: GuruTheme.fwMedium,
                                  color: negativeColor ?? guruTheme.dialogTheme.summaryColor)),
                        )),
                  ),
                  VerticalDivider(width: dialogSpec.dividerSize),
                  Expanded(
                    flex: 1,
                    child: TapWidget(
                        inkWell: true,
                        onTap: () {
                          if (guruTheme.feedbackCapabilities.canPerform()) {
                            FeedbackManager.instance.perform(FeedbackOccasion.clickButton);
                          }
                          RouteCenter.instance.back(result: AlertResult.positive);
                        },
                        child: Center(
                          child: Text(positiveButtonText,
                              textAlign: TextAlign.center,
                              style: TextStyle(
                                  fontSize: dialogSpec.buttonFontSize,
                                  fontWeight: GuruTheme.fwMedium,
                                  color: negativeColor ?? Colors.red)),
                        )),
                  ),
                ],
              ),
            )
          ],
        ));
  }
}
