import 'package:auto_size_text/auto_size_text.dart';
import 'package:design/design.dart';
import 'package:guru_widgets/common/spacer.dart';
import 'package:guru_widgets/theme/guru_theme.dart';
import 'package:guru_utils/property/settings/settings_data.dart';

/// Created by Haoyi on 2023/6/2
///
///
///
part 'guru_list_tile.g.dart';

@DesignSpec(width: 750, height: 128, specMode: SpecMode.nested)
abstract class GuruListTileDesignSpec implements BasicDesignSpec {
  @SpecEdgeInsets.only(
      start: SpecHorizontal(28),
      end: SpecHorizontal(32),
      top: SpecVertical(40),
      bottom: SpecVertical(40))
  EdgeInsetsDirectional get itemPadding;

  @SpecEdgeInsets.only(start: SpecHorizontal(28), end: SpecHorizontal(32))
  EdgeInsetsDirectional get switchItemPadding;

  @SpecEdgeInsets.only(start: SpecHorizontal(12))
  EdgeInsetsDirectional get leadingPadding;

  @SpecEdgeInsets.only(start: SpecHorizontal(40), top: SpecVertical(56), bottom: SpecVertical(28))
  EdgeInsetsDirectional get groupHeaderPadding;

  @SpecAbsoluteFontSize(26)
  double get groupTitleFontSize;

  @SpecEdgeInsets.only(start: SpecHorizontal(48), top: SpecVertical(16), bottom: SpecVertical(48))
  EdgeInsetsDirectional get descriptionPadding;

  @SpecAbsoluteFontSize(24)
  double get descriptionFontSize;

  @SpecHeight(48)
  double get leadingSize;

  @SpecEdgeInsets.symmetric(horizontal: SpecHorizontal(20))
  EdgeInsetsDirectional get titlePadding;

  @SpecAbsoluteFontSize(32)
  double get titleFontSize;

  @SpecAbsoluteFontSize(4)
  double get summaryTopSpacing;

  @SpecAbsoluteFontSize(20)
  double get summaryFontSize;

  @SpecHeight(48)
  double get trailingSize;

  @SpecAspectHeightSize(72, 1.44444444)
  Size get switchBarSize;

  @SpecHeight(1)
  double get dividerHeight;

  @SpecHorizontal(40)
  double get dividerIndent;

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

abstract class GuruTile extends StatelessWidget {
  const GuruTile({Key? key}) : super(key: key);

  Widget buildTile({
    required GuruListTileDesignSpec designSpec,
    required GuruListTileTheme tileTheme,
    required GuruColorScheme colorScheme,
    required Widget child,
    VoidCallback? onTap,
  }) {
    return Material(
        color: tileTheme.backgroundColor ?? colorScheme.containerColor ?? Colors.white,
        child: ConstrainedBox(
          constraints: BoxConstraints(minHeight: designSpec.measuredSize.height),
          child: Ink(
              child: InkWell(
                  onTap: () {
                    onTap?.call();
                  },
                  child: child)),
        ));
  }
}

class GuruListTile extends GuruTile {
  final double? width;
  final double? height;
  final String title;
  final String? summary;
  final String? leading;
  final String? trailing;
  final TextStyle? titleTextStyle;
  final VoidCallback? onTap;

  const GuruListTile(
      {required this.title,
      this.width,
      this.height,
      this.summary,
      this.leading,
      this.trailing,
      this.titleTextStyle,
      this.onTap,
      Key? key})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    final guruTheme = GuruTheme.of(context);
    final colorScheme = guruTheme.colorScheme;
    final designSpec = guruTheme.designSpec.pageListTileDesignSpec;
    final tileTheme = GuruTheme.of(context).listTileTheme;

    final items = <Widget>[];
    if (leading != null) {
      items.add(Padding(
        padding: designSpec.leadingPadding,
        child: Image.asset(leading!,
            width: designSpec.leadingSize,
            height: designSpec.leadingSize,
            color: tileTheme.primaryContentColor ?? colorScheme.primaryContentColor),
      ));
    }

    items.add(Expanded(
      flex: 1,
      child: Padding(
          padding: designSpec.titlePadding,
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text(title,
                  style: titleTextStyle ??
                      TextStyle(
                          fontSize: designSpec.titleFontSize,
                          fontWeight: GuruTheme.fwMedium,
                          color: tileTheme.primaryContentColor ??
                              colorScheme.primaryContentColor ??
                              Colors.black)),
              if (summary != null)
                Text(summary!,
                    style: titleTextStyle ??
                        TextStyle(
                            fontSize: designSpec.titleFontSize,
                            fontWeight: GuruTheme.fwMedium,
                            color: tileTheme.primaryContentColor ??
                                colorScheme.primaryContentColor ??
                                Colors.black))
            ],
          )),
    ));

    if (trailing != null) {
      items.add(Image.asset(
        trailing!,
        width: designSpec.trailingSize,
        height: designSpec.trailingSize,
        color: tileTheme.primaryContentColor ?? colorScheme.primaryContentColor,
      ));
    }
    return buildTile(
        designSpec: designSpec,
        tileTheme: tileTheme,
        colorScheme: colorScheme,
        child: Padding(
          padding: designSpec.itemPadding,
          child: Row(children: items),
        ),
        onTap: onTap);
  }
}

class GuruCheckedListTile extends GuruTile {
  final String title;
  final String? summary;
  final String? leading;
  final VoidCallback? onTap;
  final bool checked;

  const GuruCheckedListTile(
      {required this.title,
      required this.checked,
      this.summary,
      this.leading,
      this.onTap,
      Key? key})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    final guruTheme = GuruTheme.of(context);
    final colorScheme = guruTheme.colorScheme;
    final designSpec = guruTheme.designSpec.pageListTileDesignSpec;
    final tileTheme = GuruTheme.of(context).listTileTheme;
    final iconScheme = guruTheme.iconScheme;

    final items = <Widget>[];
    if (leading != null) {
      items.add(Padding(
        padding: designSpec.leadingPadding,
        child: Image.asset(leading!,
            width: designSpec.leadingSize,
            height: designSpec.leadingSize,
            color: tileTheme.primaryContentColor ?? colorScheme.primaryContentColor),
      ));
    }

    items.add(Expanded(
      flex: 1,
      child: Padding(
          padding: designSpec.titlePadding,
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text(title,
                  style: TextStyle(
                      fontSize: designSpec.titleFontSize,
                      fontWeight: GuruTheme.fwMedium,
                      color: tileTheme.primaryContentColor ??
                          colorScheme.primaryContentColor ??
                          Colors.black)),
              if (summary != null)
                Text(summary!,
                    style: TextStyle(
                        fontSize: designSpec.titleFontSize,
                        fontWeight: GuruTheme.fwMedium,
                        color: tileTheme.secondaryContentColor ??
                            colorScheme.secondaryContentColor ??
                            Colors.grey)),
            ],
          )),
    ));

    if (checked) {
      if (iconScheme.checkedIcon != null) {
        items.add(Image.asset(
          iconScheme.checkedIcon!,
          width: designSpec.trailingSize,
          height: designSpec.trailingSize,
          color: colorScheme.primaryColor,
        ));
      } else {
        items.add(Icon(
          Icons.check_box_outlined,
          size: designSpec.trailingSize,
          color: colorScheme.primaryColor,
        ));
      }
    } else {
      if (iconScheme.uncheckedIcon != null) {
        items.add(Image.asset(
          iconScheme.uncheckedIcon!,
          width: designSpec.trailingSize,
          height: designSpec.trailingSize,
          color: colorScheme.primaryColor,
        ));
      } else {
        items.add(Icon(
          Icons.check_box_outline_blank,
          size: designSpec.trailingSize,
          color: colorScheme.primaryColor,
        ));
      }
    }

    return buildTile(
        designSpec: designSpec,
        tileTheme: tileTheme,
        colorScheme: colorScheme,
        child: Padding(
          padding: designSpec.itemPadding,
          child: Row(children: items),
        ),
        onTap: onTap);
  }
}

class GuruSwitchListTile extends GuruTile {
  final String title;
  final String? leading;
  final bool enabled;
  final ValueChanged<bool>? onChanged;

  const GuruSwitchListTile(
      {required this.title, required this.enabled, this.leading, this.onChanged, Key? key})
      : super(key: key);

  Widget buildSwitch(GuruThemeData guruTheme) {
    final iconScheme = guruTheme.iconScheme;
    final designSpec = guruTheme.designSpec.pageListTileDesignSpec;
    if (iconScheme.switchOnIcon != null && iconScheme.switchOffIcon != null) {
      return Image.asset(
        enabled ? iconScheme.switchOnIcon! : iconScheme.switchOffIcon!,
        width: designSpec.switchBarSize.width,
        height: designSpec.switchBarSize.height,
      );
    } else {
      return SizedBox(
          width: designSpec.switchBarSize.width,
          height: designSpec.switchBarSize.height,
          child: Switch(
            value: enabled,
            onChanged: (value) {
              onChanged?.call(value);
            },
          ));
    }
  }

  @override
  Widget build(BuildContext context) {
    final guruTheme = GuruTheme.of(context);
    final tileTheme = guruTheme.listTileTheme;
    final designSpec = guruTheme.designSpec.pageListTileDesignSpec;
    final colorScheme = guruTheme.colorScheme;
    final items = <Widget>[];
    if (leading != null) {
      items.add(Padding(
        padding: designSpec.leadingPadding,
        child: Image.asset(leading!,
            width: designSpec.leadingSize,
            height: designSpec.leadingSize,
            color: tileTheme.primaryContentColor ?? colorScheme.primaryContentColor),
      ));
    }

    items.add(Expanded(
      flex: 1,
      child: Padding(
          padding: designSpec.titlePadding,
          child: Text(title,
              style: TextStyle(
                  fontSize: designSpec.titleFontSize,
                  fontWeight: GuruTheme.fwMedium,
                  color: tileTheme.primaryContentColor ??
                      colorScheme.primaryContentColor ??
                      Colors.black))),
    ));

    items.add(buildSwitch(guruTheme));
    return buildTile(
        designSpec: designSpec,
        tileTheme: tileTheme,
        colorScheme: colorScheme,
        child: Padding(
          padding: designSpec.switchItemPadding,
          child: Row(children: items),
        ),
        onTap: () {
          onChanged?.call(!enabled);
        });
  }
}

class GuruListTileGroup extends GuruTile {
  final String? title;
  final List<Widget> tiles;

  const GuruListTileGroup({Key? key, this.title, this.tiles = const <GuruTile>[]})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    final guruTheme = GuruTheme.of(context);
    final listTileTheme = guruTheme.listTileTheme;
    final colorScheme = guruTheme.colorScheme;
    final designSpec = guruTheme.designSpec.pageListTileDesignSpec;

    final decoratedGroupTile = DecoratedBox(
      decoration: BoxDecoration(
          color: listTileTheme.backgroundColor ?? colorScheme.containerColor ?? Colors.white),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        mainAxisSize: MainAxisSize.min,
        children: tiles,
      ),
    );

    if (title == null) {
      return decoratedGroupTile;
    }

    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        ...[
          Padding(
            padding: designSpec.groupHeaderPadding,
            child: Text(
              title ?? '',
              style: TextStyle(
                  fontSize: designSpec.groupTitleFontSize,
                  fontWeight: FontWeight.w500,
                  color: listTileTheme.secondaryContentColor ??
                      guruTheme.colorScheme.secondaryContentColor),
            ),
          )
        ],
        decoratedGroupTile
      ],
    );
  }
}

class DropdownSwitchListTile<T> extends GuruTile {
  final String title;
  final bool enabled;
  final List<T> selectableValues;
  final SettingData<T> selected;
  final ValueChanged<bool>? onChanged;
  final ValueChanged<T?>? onSelected;

  const DropdownSwitchListTile(
      {required this.title,
      required this.selectableValues,
      required this.selected,
      required this.enabled,
      this.onChanged,
      this.onSelected,
      Key? key})
      : super(key: key);

  Widget buildSwitch(GuruThemeData guruTheme) {
    final iconScheme = guruTheme.iconScheme;
    final designSpec = guruTheme.designSpec.pageListTileDesignSpec;
    if (iconScheme.switchOnIcon != null && iconScheme.switchOffIcon != null) {
      return Image.asset(
        enabled ? iconScheme.switchOnIcon! : iconScheme.switchOffIcon!,
        width: designSpec.switchBarSize.width,
        height: designSpec.switchBarSize.height,
      );
    } else {
      return SizedBox(
          width: designSpec.switchBarSize.width,
          height: designSpec.switchBarSize.height,
          child: Switch(
            value: enabled,
            onChanged: (value) {
              onChanged?.call(value);
            },
          ));
    }
  }

  Widget buildDropdown() {
    return StreamBuilder<T>(
        stream: selected.observe(),
        builder: (context, snapshot) {
          return DropdownButton<T>(
            value: snapshot.data,
            dropdownColor: const Color.fromARGB(255, 72, 72, 72),
            style: const TextStyle(color: Colors.white),
            underline: Container(),
            onChanged: (T? value) {
              selected.set(value);
              onSelected?.call(value);
            },
            items: selectableValues.map<DropdownMenuItem<T>>((T value) {
              return DropdownMenuItem<T>(
                value: value,
                child: Text(value.toString()),
              );
            }).toList(),
          );
        });
  }

  @override
  Widget build(BuildContext context) {
    final guruTheme = GuruTheme.of(context);
    final tileTheme = guruTheme.listTileTheme;
    final designSpec = guruTheme.designSpec.pageListTileDesignSpec;
    final colorScheme = guruTheme.colorScheme;
    final items = <Widget>[];

    items.add(Expanded(
      flex: 3,
      child: Padding(
          padding: designSpec.titlePadding,
          child: AutoSizeText(title,
              minFontSize: 10,
              maxLines: 1,
              style: TextStyle(
                  fontSize: designSpec.titleFontSize,
                  fontWeight: GuruTheme.fwMedium,
                  color: tileTheme.primaryContentColor ??
                      colorScheme.primaryContentColor ??
                      Colors.black))),
    ));
    items.add(const VerticalDivider(
      thickness: 1,
      indent: 10,
      endIndent: 10,
      color: Colors.grey,
    ));
    items.add(Expanded(
        flex: 4, child: Padding(padding: designSpec.titlePadding, child: buildDropdown())));
    items.add(buildSwitch(guruTheme));
    return buildTile(
        designSpec: designSpec,
        tileTheme: tileTheme,
        colorScheme: colorScheme,
        child: Padding(
          padding: designSpec.switchItemPadding,
          child: Row(mainAxisSize: MainAxisSize.max, children: items),
        ));
  }
}
