import 'dart:developer';

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/int_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/lookup.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/multiple_selection_fullscreen_dialog.dart';
import 'package:test_sa/views/widgets/fullscreen_dialogs/selection_fullscreen_dialog.dart';

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

class MultipleItemDropDownMenu<T extends Base, X extends LoadingListNotifier> extends StatefulWidget {
  final BuildContext context;
  final Function(List<T>?)? onSelect; // Now accepts nullable values
  final List<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 bool? loading; // Now nullable
  final int? requestById; // Now nullable

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

  @override
  State<MultipleItemDropDownMenu<T, X>> createState() => _MultipleItemDropDownMenuState<T, X>();
}

class _MultipleItemDropDownMenuState<T extends Base, X extends LoadingListNotifier> extends State<MultipleItemDropDownMenu<T, X>> {
  List<T> _selectedItem = [];
  X? provider;

  @override
  void initState() {
    if (X != NullableLoadingProvider) {
      provider = Provider.of<X>(widget.context);
    }

    if (widget.initialValue.isNotEmpty) {
      // Get the source list
      final sourceList = (X == NullableLoadingProvider ? widget.staticData : provider?.items);

      if (sourceList != null && sourceList.isNotEmpty) {
        // Collect matches based on identifier or name
        // For Lookup: compare by id/value; For others: compare by identifier/name
        final results = sourceList.where((element) {
          return widget.initialValue!.any((init) {
            // Try Lookup-specific comparison first (id/value)
            if (element is Lookup && init is Lookup) {
              return (element.id != null && element.id == init.id) ||
                     (element.value != null && element.value == init.value);
            }
            // Fallback to identifier comparison
            if (element.identifier != null && init.identifier != null) {
              return element.identifier == init.identifier;
            }
            // Last resort: name comparison
            return element.name != null && element.name == init.name;
          });
        }).toList();

        if (results.isNotEmpty) {
          _selectedItem
            ..clear()
            ..addAll(results.cast<T>());

          // Don't call onSelect in initState - parent already has the initialValue
        }
      }
    }

    super.initState();
  }

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

  @override
  void didUpdateWidget(covariant MultipleItemDropDownMenu<T, X> oldWidget) {
    // Only update if initialValue actually changed from the old widget
    if (_hasInitialValueChanged(oldWidget)) {
      if (widget.initialValue.isNotEmpty) {
        // Get the source list
        final sourceList = (X == NullableLoadingProvider ? widget.staticData : provider?.items);
        if (sourceList != null && sourceList.isNotEmpty) {
          // Collect matches based on identifier or name
          // For Lookup: compare by id/value; For others: compare by identifier/name
          final results = sourceList.where((element) {
            return widget.initialValue!.any((init) {
              // Try Lookup-specific comparison first (id/value)
              if (element is Lookup && init is Lookup) {
                return (element.id != null && element.id == init.id) ||
                       (element.value != null && element.value == init.value);
              }
              // Fallback to identifier comparison
              if (element.identifier != null && init.identifier != null) {
                return element.identifier == init.identifier;
              }
              // Last resort: name comparison
              return element.name != null && element.name == init.name;
            });
          }).toList();

          if (results.isNotEmpty) {
            _selectedItem
              ..clear()
              ..addAll(results.cast<T>());

            // Don't call onSelect here - it will create infinite loop
            // The parent already has the correct value
          }
        }
      } else {
        // initialValue is empty, clear selection
        _selectedItem.clear();
      }
    }
    super.didUpdateWidget(oldWidget);
  }

  bool _hasInitialValueChanged(MultipleItemDropDownMenu<T, X> oldWidget) {
    if (oldWidget.initialValue.length != widget.initialValue.length) {
      return true;
    }
    if (widget.initialValue.isEmpty && oldWidget.initialValue.isEmpty) {
      return false;
    }
    // Compare items by identifier/id/value
    for (int i = 0; i < widget.initialValue.length; i++) {
      final current = widget.initialValue[i];
      final hasMatch = oldWidget.initialValue.any((old) {
        // Try Lookup-specific comparison first (id/value)
        if (old is Lookup && current is Lookup) {
          return (old.id != null && old.id == current.id) ||
                 (old.value != null && old.value == current.value);
        }
        // Fallback to identifier comparison
        if (old.identifier != null && current.identifier != null) {
          return old.identifier == current.identifier;
        }
        // Last resort: name comparison
        return old.name != null && old.name == current.name;
      });

      if (!hasMatch) {
        return true;
      }
    }
    return false;
  }

  @override
  Widget build(BuildContext context) {
    final isEmpty = (X == NullableLoadingProvider ? widget.staticData : provider?.items)?.isEmpty ?? true;

    // Determine the actual loading state - respect explicit loading prop and enabled state
    final bool isActuallyLoading = widget.enabled
        ? (widget.loading ?? ((X == NullableLoadingProvider) ? false : provider?.loading ?? false))
        : false; // Never show loading when disabled

    // Provide a valid stateCode when disabled to prevent AppLoadingManager from auto-fetching
    // When enabled, use the provider's actual stateCode
    final int? effectiveStateCode = widget.enabled
        ? ((X == NullableLoadingProvider) ? 200 : provider?.stateCode)
        : 200; // Return 200 when disabled to indicate "loaded" state (prevents auto-fetch)

    return AppLoadingManager(
      isLoading: isActuallyLoading,
      isFailedLoading: widget.enabled && (X == NullableLoadingProvider) ? false : provider?.items == null,
      stateCode: effectiveStateCode,
      onRefresh: () async {
        // Simple check: Only fetch data if the widget is enabled
        if (!widget.enabled) return;

        if (X != NullableLoadingProvider) {
          provider?.reset();
          await provider?.getData(id: widget.requestById);
        }
      },
      child: Container(
        // height: widget.height ?? 60.toScreenHeight,
        padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 8.toScreenHeight),
        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),
          boxShadow: widget.showShadow ? [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)] : null,
        ),
        child: Row(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              mainAxisAlignment: MainAxisAlignment.center,
              mainAxisSize: MainAxisSize.min,
              children: [
                Flexible(
                  child: Text(widget.title, style: TextStyle(fontWeight: FontWeight.w500, fontSize: context.isTablet() ? 16 : 12, color: AppColor.floatingTextStyleColor(context))),
                ),
                4.height,
                if (_selectedItem.isEmpty)
                  Text(
                    context.translation.select,
                    style: Theme.of(context).textTheme.bodyLarge,
                  )
                else
                  Wrap(
                    runSpacing: 4.toScreenHeight,
                    spacing: 4.toScreenWidth,
                    children: List.generate(
                      _selectedItem.length,
                      (index) => AnimatedSize(
                        duration: const Duration(milliseconds: 300),
                        curve: Curves.easeInOut,
                        child: AnimatedOpacity(
                          opacity: _selectedItem.contains(_selectedItem[index]) ? 1.0 : 0.0,
                          duration: const Duration(milliseconds: 300),
                          curve: Curves.easeInOut,
                          child: Theme(
                            data: Theme.of(context).copyWith(
                              splashColor: Colors.transparent,
                              highlightColor: Colors.transparent,
                            ),
                            child: Chip(
                              backgroundColor: AppColor.backgroundTabBarColor(context),
                              side: BorderSide(color: AppColor.border2Color(context)),
                              label: Text(_selectedItem[index].name!),
                              shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(30.0)),
                              labelStyle: AppTextStyles.tinyFont2.copyWith(
                                color: AppColor.labelTextStyleColor(context),
                              ),
                              deleteIconColor: AppColor.icon2Color(context),
                              materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
                              onDeleted: () {
                                setState(() {
                                  _selectedItem.removeAt(index);
                                });
                                widget.onSelect!(_selectedItem);
                              },
                            ),
                          ),
                        ),
                      ),
                    ),
                  ).paddingOnly(top: 4),
              ],
            )
                .onPress(
                  widget.enabled && widget.showAsFullScreenDialog
                      ? () {
                          openDialog();
                        }
                      : null,
                )
                .expanded,
            if (widget.enabled) const Icon(Icons.keyboard_arrow_down_rounded).paddingOnly(top: 4),
          ],
        ),
      ),
    );
  }

  void openDialog() async {
    Widget child = MultipleSelectionFullScreenDialog<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;
        });
        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));
  }
}
