import 'package:fis_theme/theme.dart';
import 'package:fis_ui/index.dart';
import 'package:fis_ui/widgets/custom_dropdown_button.dart' as custom_widget;
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flyinsono/architecture/define.dart';

///FIS的选择组件的值提取器函数声明
typedef FSelectValueExtractor<TOut, T> = TOut Function(T data);

///FIS选择组件控制器
class FSelectController<T> extends ChangeNotifier {
  FSelectController({
    Iterable<T> initialValue = const [],
    T? selection,
  }) {
    _selection = selection;
    _options = initialValue;
  }

  late Iterable<T> _options;
  Iterable<T> get options => _options;

  ///设置选项
  set options(Iterable<T> val) {
    _options = val;
    notifyListeners();
  }

  ///清空选项
  void clear() {
    selection = null;
    options = [];
  }

  late T? _selection;
  T? get selection => _selection;

  ///设置选项
  set selection(T? val) {
    if (_selection != val) {
      _selection = val;
      notifyListeners();
    }
  }
}

///FIS选择器
class FSelect<T, TValue> extends StatefulWidget implements FWidget {
  FSelect({
    Key? key,
    required this.controller,
    required this.valueExtractor,
    required this.labelExtractor,
    this.onSelectChanged,
    this.hint,
    this.left,
    this.bottom,
    this.right,
    this.top,
    this.fontSize,
    this.focusNode,
    this.boxDecoration,
    this.itemHeight = 35,
  }) : super(key: key);

  ///控制器
  final FSelectController<T> controller;

  ///值提取器
  final FSelectValueExtractor<TValue, T> valueExtractor;

  ///标签提取器
  final FSelectValueExtractor<String, T> labelExtractor;

  ///值变化回调事件函数
  final ValueCallback<T?>? onSelectChanged;

  ///提示信息
  final String? hint;

  ///字体大小
  final int? fontSize;

  ///鼠标焦点选中结点
  final FocusNode? focusNode;

  ///左边距
  final double? left;

  ///下边距
  final double? bottom;

  ///右边距
  final double? right;

  ///上边距
  final double? top;

  ///外围装饰器
  final BoxDecoration? boxDecoration;

  /// 新增下拉框高度
  final double? itemHeight;

  @override
  State<FSelect<T, TValue>> createState() => _FSelectState<T, TValue>();
}

///FIS的选择器状态
class _FSelectState<T, TValue> extends State<FSelect<T, TValue>> {
  @override
  FWidget build(BuildContext context) {
    final items = <custom_widget.DropdownMenuItem<T>>[];
    final data = widget.controller.options;
    final len = data.length;
    for (var i = 0; i < len; i++) {
      final option = data.elementAt(i);
      items.add(
        custom_widget.DropdownMenuItem(
          child: _SelectOption(
            widget.labelExtractor(option),
            left: widget.left,
            active: _optionEquals(option, widget.controller.selection),
            fontSize: widget.fontSize,
          ),
          value: option,
        ),
      );
    }

    final btn = custom_widget.FCustomDropdownButtonStyle(
      child: custom_widget.FCustomDropdownButton<T>(
        itemHeight: widget.itemHeight,
        items: items,
        selectedItemBuilder: (_) => data
            .map(
              (e) => _SelectOption(
                widget.labelExtractor(e),
                overt: true,
                left: widget.left,
                fontSize: widget.fontSize,
              ),
            )
            .toList(),
        isExpanded: true,
        isDense: true,
        focusNode: widget.focusNode,
        value: widget.controller.selection,
        underline: FContainer(),
        elevation: 6,
        iconEnabledColor: Color(0xffa0a0a0),
        menuMaxHeight: 350.0,
        hint: widget.hint != null
            ? FContainer(
                padding: EdgeInsets.only(left: widget.left ?? 0),
                child: FText(
                  widget.hint!,
                  style: TextStyle(
                    color: Colors.grey,
                    fontSize:
                        widget.fontSize == null ? 14.sp : widget.fontSize!.sp,
                  ),
                ),
              )
            : null,
        onChanged: (T? value) {
          widget.onSelectChanged?.call(value);
        },
      ),
      padding: EdgeInsets.only(left: 15),
    );

    return FContainer(
      padding: EdgeInsets.only(
        bottom: widget.bottom ?? 0,
        top: widget.top ?? 0,
      ),
      margin: EdgeInsets.only(right: widget.right ?? 0),
      decoration: widget.boxDecoration ?? BoxDecoration(),
      child: QuickFWidget(btn),
    );
  }

  @override
  void initState() {
    widget.controller.addListener(_updateOptionsData);
    super.initState();
  }

  void _updateOptionsData() {
    if (mounted) {
      setState(() {});
    }
  }

  bool _optionEquals(T? a, T? b) {
    if (a == null && b == null) return true;
    if (a == null || b == null) return false;
    return widget.valueExtractor(a) == widget.valueExtractor(b);
  }
}

///选择选项
class _SelectOption extends StatelessWidget {
  _SelectOption(
    this.title, {
    this.active = false,
    this.overt = false,
    this.fontSize = 14,
    this.left,
  });
  final String title;
  final int? fontSize;
  final bool active;
  final bool overt;
  final double? left;

  @override
  FWidget build(BuildContext context) {
    final colorScheme = FTheme.ins.colorScheme;
    return FContainer(
      padding: EdgeInsets.only(left: left ?? 0),
      child: OverflowDetectorText(
        child: FText(
          title,
          maxLines: 1,
          overflow: TextOverflow.ellipsis,
          style: TextStyle(
            color: overt
                ? FInput.txtColor
                : active
                    ? colorScheme.primary
                    : Colors.grey,
            fontSize: fontSize == null ? 14.sp : fontSize!.sp,
            fontFamily: FTheme.ins.localeSetting.fontFamily,
            fontFamilyFallback: [
              FTheme.ins.data.localeSettings.chinese.fontFamily,
            ],
          ),
        ),
      ),
    );
  }
}

class OverflowDetectorText extends FStatelessWidget {
  final FText child;
  final DisplayPosition position;
  final Offset offset;

  OverflowDetectorText({
    Key? key,
    required this.child,
    this.position = DisplayPosition.top,
    this.offset = const Offset(0, -3),
  })  : assert(
          child.style != null && child.style!.fontFamily != null,
          'child must have a non-null style with a non-null fontFamily',
        ),
        super(key: key);

  @override
  FWidget build(BuildContext context) {
    var tp = TextPainter(
      maxLines: child.maxLines,
      textAlign: child.textAlign ?? TextAlign.start,
      textDirection: child.textDirection ?? TextDirection.ltr,
      text: child.textSpan ??
          TextSpan(
            text: child.data,
            style: child.style,
          ),
    );

    return FLayoutBuilder(
      builder: (context, constrains) {
        tp.layout(maxWidth: constrains.maxWidth);
        final overflowed = tp.didExceedMaxLines;
        if (overflowed) {
          return FTextTooltip(
            position: position,
            offset: offset,
            message: child.data ?? '',
            child: child,
          );
        }
        return child;
      },
    );
  }
}
