import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/enum_extensions.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/new_views/app_style/app_text_style.dart';
import 'package:test_sa/new_views/common_widgets/app_loading_manager.dart';
import 'package:test_sa/providers/loading_list_notifier.dart';
import 'package:test_sa/views/widgets/bottom_sheets/selection_bottom_sheet.dart';
import 'package:test_sa/views/widgets/fullscreen_dialogs/selection_fullscreen_dialog.dart';

import '../../models/base.dart';
import '../app_style/app_color.dart';

class SingleItemDropDownMenu<T extends Base, X extends LoadingListNotifier> extends StatefulWidget {
  final BuildContext context;
  final Function(T?)? onSelect; // Now accepts nullable values
  final T? initialValue;
  final T? disableValue;
  final bool enabled;
  final bool showAsBottomSheet;
  final bool showAsFullScreenDialog;
  final List<T>? staticData;
  final String title;
  final double? height;
  final bool showShadow;
  final bool showCancel;
  final Color? backgroundColor; // Now nullable
  final Color? titleTextColor; // Now nullable
  final bool? loading; // Now nullable
  final int? requestById;
  final VoidCallback? infoCallback;
  final String? Function(T?)? validator;
  final AutovalidateMode? autovalidateMode;
  final DropDownMatchType matchBy;

  /// To use a static data (without calling API)
  /// just send [NullableLoadingProvider] as generic data type and fill the [staticData]
  const SingleItemDropDownMenu({
    Key? key,
    this.title = "",
    required this.context,
    this.onSelect,
    this.initialValue,
    this.disableValue,
    this.enabled = true,
    this.height,
    this.infoCallback,
    this.showAsBottomSheet = false,
    this.showAsFullScreenDialog = true,
    this.staticData, // Provide a default empty list
    this.showShadow = true,
    this.showCancel = false,
    this.backgroundColor,
    this.titleTextColor,
    this.loading,
    this.requestById,
    this.validator,
    this.autovalidateMode,
    this.matchBy = DropDownMatchType.identifier,
  }) : super(key: key);

  @override
  State<SingleItemDropDownMenu<T, X>> createState() => _SingleItemDropDownMenuState<T, X>();
}

class _SingleItemDropDownMenuState<T extends Base, X extends LoadingListNotifier> extends State<SingleItemDropDownMenu<T, X>> {
  T? _selectedItem;
  X? provider;

  @override
  void initState() {
    super.initState();
    if (X != NullableLoadingProvider) {
      provider = Provider.of<X>(widget.context);
    }
    if (widget.initialValue == null) return;
    final List<T>? items = (X == NullableLoadingProvider ? widget.staticData : provider?.items)?.cast<T>();

    if (items == null || items.isEmpty) return;
    final Iterable<T> matches = items.where((e) => _isSameItem(e, widget.initialValue!));

    if (matches.isNotEmpty) {
      _selectedItem = matches.first;
    } else {
      _selectedItem = null;
    }
    if (widget.onSelect != null && !_isSameItem(widget.initialValue!, _selectedItem ?? widget.initialValue!)) {
      widget.onSelect!(_selectedItem);
    }
  }

  // @override
  // void initState() {
  //   if (X != NullableLoadingProvider) {
  //     provider = Provider.of<X>(widget.context);
  //   }
  //   if (widget.initialValue != null) {
  //     final result = (X == NullableLoadingProvider ? widget.staticData : provider?.items)?.where((element) => element.identifier == widget.initialValue?.identifier);
  //     if (result?.isNotEmpty ?? false) _selectedItem = result!.first as T?;
  //     if (widget.onSelect != null && (widget.initialValue?.identifier ?? "") != (_selectedItem?.identifier ?? "")) {
  //       widget.onSelect!(_selectedItem); // Non-null assertion after null check
  //     }
  //   }
  //   super.initState();
  // }

  @override
  void setState(VoidCallback fn) {
    if (mounted) super.setState(fn);
  }

  bool _isSameItem(Base a, Base b) {
    switch (widget.matchBy) {
      case DropDownMatchType.name:
        return (a.name ?? '') == (b.name ?? '');
      case DropDownMatchType.identifier:
      default:
        return (a.identifier ?? '') == (b.identifier ?? '');
    }
  }

  // @override
  // void didUpdateWidget(covariant SingleItemDropDownMenu<T, X> oldWidget) {
  //   if (widget.initialValue != null) {
  //     final result = (X == NullableLoadingProvider ? widget.staticData : provider?.items)?.where((element) => element.identifier == widget.initialValue?.identifier);
  //
  //     if (result?.isNotEmpty ?? false) {
  //       _selectedItem = result?.first as T?;
  //     } else {
  //       _selectedItem = null;
  //     }
  //     if (widget.onSelect != null && (widget.initialValue?.identifier ?? "") != (_selectedItem?.identifier ?? "")) {
  //       widget.onSelect!(_selectedItem); // Non-null assertion after null check
  //     }
  //   } else {
  //     _selectedItem = null;
  //   }
  //   super.didUpdateWidget(oldWidget);
  // }
  @override
  void didUpdateWidget(covariant SingleItemDropDownMenu<T, X> oldWidget) {
    super.didUpdateWidget(oldWidget);

    // Get old and new items lists
    final List<T>? oldItems = (X == NullableLoadingProvider ? oldWidget.staticData : provider?.items)?.cast<T>();
    final List<T>? newItems = (X == NullableLoadingProvider ? widget.staticData : provider?.items)?.cast<T>();

    // Check if items list has changed (provider loaded new data)
    final bool itemsChanged = (oldItems?.length ?? 0) != (newItems?.length ?? 0);

    // Skip update only if initialValue hasn't changed AND items haven't changed AND we already have a selected item
    if (oldWidget.initialValue == widget.initialValue && !itemsChanged && _selectedItem != null) return;

    if (widget.initialValue == null) {
      _selectedItem = null;
      return;
    }

    T? matchedItem;

    if (newItems != null && newItems.isNotEmpty) {
      final Iterable<T> matches = newItems.where((e) => _isSameItem(e, widget.initialValue!));

      if (matches.isNotEmpty) matchedItem = matches.first;
    }

    // Only update if we found a match or if _selectedItem was previously null
    if (matchedItem != null || _selectedItem == null) {
      _selectedItem = matchedItem;
    }

    // Only call onSelect if the matched item is different from what we had before
    if (widget.onSelect != null && matchedItem != null && !_isSameItem(widget.initialValue!, _selectedItem ?? widget.initialValue!)) {
      widget.onSelect!(_selectedItem);
    }
  }

  @override
  Widget build(BuildContext context) {
    // If using a provider, wrap with Consumer to react to changes
    if (X != NullableLoadingProvider && provider != null) {
      return Consumer<X>(
        builder: (context, providerValue, child) {
          // When provider items change, try to match the initialValue
          final List<T>? items = providerValue.items?.cast<T>();
          if (widget.initialValue != null && items != null && items.isNotEmpty && _selectedItem == null) {
            WidgetsBinding.instance.addPostFrameCallback((_) {
              final Iterable<T> matches = items.where((e) => _isSameItem(e, widget.initialValue!));
              if (matches.isNotEmpty) {
                setState(() {
                  _selectedItem = matches.first;
                });
              }
            });
          }
          return _buildFormField(context);
        },
      );
    }
    return _buildFormField(context);
  }

  Widget _buildFormField(BuildContext context) {
    final isEmpty = (X == NullableLoadingProvider ? widget.staticData : provider?.items)?.isEmpty ?? true;
    return FormField<T>(
        validator: widget.validator,
        autovalidateMode: widget.autovalidateMode ?? AutovalidateMode.disabled,
        initialValue: widget.initialValue,
        builder: (FormFieldState<T> fieldState) {
          return Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              AppLoadingManager(
                isLoading: widget.loading ?? ((X == NullableLoadingProvider) ? false : provider?.loading ?? false),
                // Provide default value if null
                isFailedLoading: (X == NullableLoadingProvider) ? false : provider?.items == null,
                stateCode: (X == NullableLoadingProvider) ? 200 : provider?.stateCode,
                onRefresh: () async {
                  if (X != NullableLoadingProvider) {
                    provider?.reset();
                    await provider?.getData(id: widget.requestById);
                  }
                },
                child: Container(
                  height: widget.height ?? 60.toScreenHeight,
                  padding: EdgeInsets.only(left: 16.toScreenWidth, right: 8.toScreenWidth),
                  decoration: BoxDecoration(
                    color: context.isDark && (widget.enabled == false || isEmpty)
                        ? AppColor.disableDark
                        : (widget.enabled == false || isEmpty)
                            ? AppColor.neutral40
                            : AppColor.dropDownBackground(context),
                    borderRadius: BorderRadius.circular(16),
                    border: Border.all(color: AppColor.border2Color(context), width: 1),
                    //  side: RoundedRectangleBorder(borderRadius: BorderRadius.circular(borderRadius), side: BorderSide(color: AppColor.borderColor(context))),
                    //  border: BorderSi//de(color: AppColor.borderColor(context)),
                    boxShadow: widget.showShadow ? [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)] : null,
                  ),
                  child: Row(
                    children: [
                      Stack(
                        alignment: Alignment.center,
                        children: [
                          if (widget.enabled) const PositionedDirectional(end: 0, child: Icon(Icons.keyboard_arrow_down_rounded)),
                          Column(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            mainAxisAlignment: MainAxisAlignment.center,
                            children: [
                              Flexible(
                                child: Text(widget.title, style: TextStyle(fontWeight: FontWeight.w500, fontSize: context.isTablet() ? 16 : 12, color: AppColor.floatingTextStyleColor(context))),
                              ),
                              DropdownButton<T>(
                                value: _selectedItem,
                                iconSize: 24,
                                isDense: true,
                                icon: const SizedBox.shrink(),
                                dropdownColor: AppColor.neutral100,
                                elevation: 0,
                                isExpanded: true,
                                hint: Text(
                                  isEmpty || widget.enabled == false ? context.translation.noDataFound : context.translation.select,
                                  style: AppTextStyles.bodyText.copyWith(color: AppColor.textStyleColor(context)),
                                ),
                                // style: TextStyle(color: Theme.of(context).primaryColor, fontSize: 12),
                                underline: const SizedBox.shrink(),
                                onChanged: (widget.enabled == false || widget.showAsBottomSheet || widget.showAsFullScreenDialog)
                                    ? null
                                    : (T? newValue) {
                                        // Now accepts nullable values
                                        final isNull = newValue?.identifier == "-1";
                                        setState(() {
                                          _selectedItem = isNull ? null : newValue;
                                        });
                                        fieldState.didChange(isNull ? null : newValue);
                                        widget.onSelect!(isNull ? null : newValue);
                                      },
                                items: ((X == NullableLoadingProvider) ? widget.staticData : provider?.items as List<T>)?.map<DropdownMenuItem<T>>((value) {
                                  return DropdownMenuItem<T>(
                                    value: value,
                                    child: Text(value.name ?? "", // Null-aware operator for value.name
                                        maxLines: 1,
                                        overflow: TextOverflow.ellipsis,
                                        style: AppTextStyles.bodyText.copyWith(color: AppColor.textStyleColor(context))
                                        //  Theme.of(context).textTheme.bodyMedium?.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.white10 : AppColor.black10),
                                        ),
                                  );
                                }).toList(),
                              ),
                            ],
                          ).onPress(widget.enabled && widget.showAsFullScreenDialog
                              ? () {
                                  openDialog(fieldState);
                                }
                              : widget.enabled
                                  ? (widget.showAsBottomSheet
                                      ? () async {
                                          final selectedT = await showModalBottomSheet<T?>(
                                            // Specify return type
                                            context: context,
                                            isScrollControlled: true,
                                            shape: const RoundedRectangleBorder(
                                              borderRadius: BorderRadius.vertical(
                                                top: Radius.circular(20),
                                              ),
                                            ),
                                            clipBehavior: Clip.antiAliasWithSaveLayer,
                                            builder: (BuildContext context) => SelectionBottomSheet<T>(
                                              // Specify generic type
                                              items: ((X == NullableLoadingProvider) ? widget.staticData : provider?.items as List<T>) ?? [],
                                              // Provide default empty list if null
                                              selectedItem: _selectedItem,
                                              title: widget.title,
                                              showCancel: widget.showCancel,
                                              onSelect: (selectedT) {
                                                setState(() {
                                                  _selectedItem = selectedT;
                                                });
                                                fieldState.didChange(selectedT);
                                                widget.onSelect!(selectedT);
                                              },
                                              builderString: (emp) => emp?.name ?? "", // Null-aware operator for emp.name
                                            ),
                                          );
                                          // if (selectedT != null) {
                                          //   setState(() {
                                          //     _selectedItem = selectedT;
                                          //   });
                                          //   widget.onSelect!(selectedT); // Non-null assertion after null check
                                          // }
                                        }
                                      : null)
                                  : null),
                        ],
                      ).expanded,
                      if (widget.infoCallback != null) Icon(Icons.info_outline_rounded, color: AppColor.icon2Color(context)).onPress(widget.infoCallback),
                    ],
                  ),
                ),
              ),
              if (fieldState.hasError)
                Padding(
                  padding: const EdgeInsets.only(left: 12, top: 4),
                  child: Text(
                    fieldState.errorText!,
                    style: AppTextStyle.tiny.copyWith(color: context.isDark ? AppColor.red50 : AppColor.red30),
                  ),
                )
            ],
          );
        });
  }

  void openDialog(FormFieldState<T> fieldState) async {
    Widget child = SelectionFullScreenDialog<T>(
      // Specify generic type
      items: ((X == NullableLoadingProvider) ? widget.staticData : provider?.items as List<T>) ?? [],
      // Provide default empty list if null
      selectedItem: _selectedItem,
      disableItem: widget.disableValue,
      title: widget.title,
      showCancel: widget.showCancel,
      onSelect: (selectedT) {
        setState(() {
          _selectedItem = selectedT;
        });
        fieldState.didChange(selectedT);
        widget.onSelect!(selectedT);
      },
      builderString: (emp) => emp?.name ?? "", // Null-aware operator for emp.name
    );
    pushRouter(child);
    // final selectedT = await pushRouter(child);
    // if (selectedT != null) {
    //   setState(() {
    //     _selectedItem = selectedT;
    //   });
    //   widget.onSelect!(selectedT); // Non-null assertion after null check
    // }
  }

  Future<T?> pushRouter(Widget child) async {
    // PageRoute<T> pRoute = !Platform.isIOS ? CupertinoPageRoute(fullscreenDialog: true, builder: (context) => child) : MaterialPageRoute(fullscreenDialog: true, builder: (context) => child);

    return await Navigator.of(context).push(CupertinoPageRoute(fullscreenDialog: true, builder: (context) => child));
  }
}
