// SPDX-FileCopyrightText: © 2025 Nøkken.io <nokken.io@proton.me>
// SPDX-License-Identifier: AGPL-3.0
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:nokken/src/core/ui/theme/app_theme.dart';
import 'package:nokken/src/core/ui/theme/app_text_styles.dart';
import 'package:nokken/src/core/ui/theme/app_colors.dart';

class DropdownWidgets {
//----------------------------------------------------------------------------
// DROPDOWN HELPER FUNCTIONS
//----------------------------------------------------------------------------

  /// A wrapper for dropdown items with optional description text
  static DropdownMenuItem<T> dropdownItemWithDescription<T>({
    required T value,
    required Widget child,
    String? description,
  }) {
    if (description == null) {
      // Regular dropdown item without description
      return DropdownMenuItem<T>(
        value: value,
        child: child,
      );
    }

    // Enhanced dropdown item with description
    return DropdownMenuItem<T>(
      value: value,
      // Use a custom tag to mark this as having a description
      // This will be detected in our custom dropdown
      child: _DropdownItemWithDescription(
        title: child,
        description: description,
      ),
    );
  }

  /// A custom dropdown that shows a semi-opaque background when showing the options
  /// Supports items with optional descriptions
  static Widget customDropdownButtonFormField<T>({
    required T value,
    required List<DropdownMenuItem<T>> items,
    required ValueChanged<T?>? onChanged,
    InputDecoration? decoration,
    Widget? hint,
    FormFieldValidator<T>? validator,
  }) {
    return Builder(
      builder: (context) {
        // Find the selected item and extract its display widget
        Widget? displayWidget;

        // Find the selected item's display widget
        for (final item in items) {
          if (item.value == value) {
            // Check if this is an item with description
            if (item.child is _DropdownItemWithDescription) {
              final enhancedItem = item.child as _DropdownItemWithDescription;
              displayWidget = enhancedItem.title;
            } else {
              displayWidget = item.child;
            }
            break;
          }
        }

        return FormField<T>(
          initialValue: value,
          validator: validator,
          builder: (state) {
            return InkWell(
              onTap: () async {
                // Show a modal with our desired semi-opaque background
                final result = await showDialog<T>(
                  context: context,
                  barrierDismissible: true,
                  barrierColor: Colors.transparent,
                  builder: (context) {
                    // Add a search controller if there are more than 8 items
                    final bool showSearch = items.length > 8;
                    final TextEditingController searchController =
                        TextEditingController();
                    final ValueNotifier<List<DropdownMenuItem<T>>>
                        filteredItems =
                        ValueNotifier<List<DropdownMenuItem<T>>>(items);

                    // Helper function to try to extract searchable text from a widget
                    String getSearchableText(Widget? widget) {
                      if (widget == null) return '';
                      if (widget is Text) {
                        return widget.data ?? '';
                      }
                      if (widget is RichText) {
                        // Simplified approach for RichText
                        return widget.text.toPlainText();
                      }
                      // For other types, we can't extract text reliably
                      return '';
                    }

                    // Function to filter items based on search text
                    void filterItems(String query) {
                      if (query.isEmpty) {
                        filteredItems.value = items;
                        return;
                      }

                      final String searchQuery = query.toLowerCase();
                      filteredItems.value = items.where((item) {
                        if (item.child is _DropdownItemWithDescription) {
                          final enhancedItem =
                              item.child as _DropdownItemWithDescription;

                          // Extract text from title and use description
                          final titleText =
                              getSearchableText(enhancedItem.title)
                                  .toLowerCase();
                          final descText =
                              enhancedItem.description.toLowerCase();

                          return titleText.contains(searchQuery) ||
                              descText.contains(searchQuery);
                        } else {
                          // Try to extract text from the child widget
                          final itemText =
                              getSearchableText(item.child).toLowerCase();
                          return itemText.contains(searchQuery);
                        }
                      }).toList();
                    }

                    return BackdropFilter(
                      filter: ImageFilter.blur(sigmaX: 8, sigmaY: 8),
                      child: Container(
                        color: AppTheme.black.withAlpha(200),
                        child: Dialog(
                          // Adjust alignment to top when search is visible
                          alignment: showSearch
                              ? Alignment.topCenter
                              : Alignment.center,
                          insetPadding: EdgeInsets.only(
                              left: 40,
                              right: 40,
                              // Less padding at top when search is visible
                              top: showSearch ? 60 : 24,
                              bottom: 24),
                          child: ConstrainedBox(
                            constraints: BoxConstraints(
                              maxWidth: 500,
                              maxHeight:
                                  MediaQuery.of(context).size.height * 0.7,
                            ),
                            child: Column(
                              mainAxisSize: MainAxisSize.min,
                              crossAxisAlignment: CrossAxisAlignment.stretch,
                              children: [
                                // Header
                                Container(
                                  padding: const EdgeInsets.symmetric(
                                      vertical: 12, horizontal: 16),
                                  child: Row(
                                      mainAxisAlignment:
                                          MainAxisAlignment.spaceBetween,
                                      children: [
                                        Text(
                                          'Select an option',
                                          style: TextStyle(
                                            fontWeight: FontWeight.bold,
                                            color: AppColors.primary,
                                          ),
                                        ),
                                        TextButton(
                                          onPressed: () {
                                            Navigator.of(context)
                                                .pop(); // Close dialog without selection
                                          },
                                          style: TextButton.styleFrom(
                                              padding:
                                                  const EdgeInsets.symmetric(
                                                      horizontal: 8,
                                                      vertical: 4),
                                              minimumSize: const Size(0, 0),
                                              tapTargetSize:
                                                  MaterialTapTargetSize
                                                      .shrinkWrap,
                                              foregroundColor: AppColors.error,
                                              backgroundColor: AppColors.error
                                                  .withAlpha(20)),
                                          child: const Text('Cancel'),
                                        ),
                                      ]),
                                ),

                                // Divider after header
                                Divider(
                                    height: 1,
                                    color: AppColors.primary.withAlpha(60)),

                                // Search bar has been moved outside the scrollable area

                                // List of items - wrapped in Expanded to avoid intrinsic sizing issues
                                // Search bar remains static while list scrolls
                                if (showSearch)
                                  Container(
                                    padding: const EdgeInsets.symmetric(
                                        horizontal: 16, vertical: 8),
                                    child: TextField(
                                      controller: searchController,
                                      decoration: InputDecoration(
                                        hintText: 'Search...',
                                        prefixIcon: const Icon(Icons.search),
                                        contentPadding:
                                            const EdgeInsets.symmetric(
                                                vertical: 8, horizontal: 12),
                                        border: OutlineInputBorder(
                                          borderRadius:
                                              BorderRadius.circular(8),
                                        ),
                                      ),
                                      onChanged: filterItems,
                                    ),
                                  ),

                                Flexible(
                                  child: ValueListenableBuilder<
                                      List<DropdownMenuItem<T>>>(
                                    valueListenable: filteredItems,
                                    builder: (context, currentItems, _) {
                                      if (currentItems.isEmpty &&
                                          searchController.text.isNotEmpty) {
                                        return Center(
                                          child: Padding(
                                            padding: const EdgeInsets.all(16),
                                            child: Text(
                                              "No matching options found",
                                              textAlign: TextAlign.center,
                                              style: TextStyle(
                                                color: AppTheme.grey,
                                                fontStyle: FontStyle.italic,
                                              ),
                                            ),
                                          ),
                                        );
                                      }

                                      return ListView.separated(
                                        shrinkWrap: true,
                                        separatorBuilder: (context, index) =>
                                            Divider(
                                          height: 1,
                                          color: AppTheme.grey.withAlpha(60),
                                          indent: 16,
                                          endIndent: 16,
                                        ),
                                        itemCount: currentItems.length,
                                        itemBuilder: (context, index) {
                                          final item = currentItems[index];
                                          bool isSelected = item.value == value;

                                          // Check if this item has a description
                                          if (item.child
                                              is _DropdownItemWithDescription) {
                                            // Extract the title and description
                                            final enhancedItem = item.child
                                                as _DropdownItemWithDescription;

                                            // Return a list tile with both title and subtitle
                                            return ListTile(
                                              contentPadding:
                                                  const EdgeInsets.symmetric(
                                                      horizontal: 16,
                                                      vertical: 8),
                                              title: enhancedItem.title,
                                              subtitle: Text(
                                                enhancedItem.description,
                                                style: TextStyle(
                                                  fontSize: 12,
                                                  color: isSelected
                                                      ? AppColors.primary
                                                      : AppTheme.white
                                                          .withAlpha(120),
                                                ),
                                              ),
                                              selected: isSelected,
                                              tileColor: isSelected
                                                  ? AppColors.primary
                                                      .withAlpha(20)
                                                  : null,
                                              onTap: () {
                                                Navigator.of(context)
                                                    .pop(item.value);
                                              },
                                            );
                                          } else {
                                            // Regular item without description
                                            return ListTile(
                                              contentPadding:
                                                  const EdgeInsets.symmetric(
                                                      horizontal: 16,
                                                      vertical: 8),
                                              title: item.child,
                                              selected: isSelected,
                                              tileColor: isSelected
                                                  ? AppColors.primary
                                                      .withAlpha(20)
                                                  : null,
                                              onTap: () {
                                                Navigator.of(context)
                                                    .pop(item.value);
                                              },
                                            );
                                          }
                                        },
                                      );
                                    },
                                  ),
                                ),
                              ],
                            ),
                          ),
                        ),
                      ),
                    );
                  },
                );
                // If user selected a value, update the form field
                if (result != null) {
                  state.didChange(result);
                  if (onChanged != null) {
                    onChanged(result);
                  }
                }
              },
              child: InputDecorator(
                decoration: (decoration ?? const InputDecoration()).copyWith(
                  errorText: state.hasError ? state.errorText : null,
                ),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                    // Display selected value (use the actual widget if available)
                    Expanded(
                      child: displayWidget ?? (hint ?? const Text('')),
                    ),
                    // Dropdown icon
                    const Icon(Icons.arrow_drop_down),
                  ],
                ),
              ),
            );
          },
        );
      },
    );
  }

  /// A multi-select dropdown widget that allows selecting multiple options
  /// Currently only used for day of week selector
  static Widget multiSelectDropdown<T>({
    required Set<T> selectedValues,
    required List<DropdownMenuItem<T>> items,
    required ValueChanged<Set<T>> onChanged,
    InputDecoration? decoration,
    String? placeholder,
    FormFieldValidator<Set<T>>? validator,
    bool Function(T)? canDeselect,
  }) {
    // Helper function to build the display widget
    Widget _buildDisplay() {
      if (selectedValues.isEmpty) {
        return Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            Text(
              placeholder ?? 'Select options...',
              style: TextStyle(
                color: AppTheme.grey,
                fontStyle: FontStyle.italic,
              ),
            ),
            const Icon(Icons.arrow_drop_down),
          ],
        );
      }

      // Create a list of display texts for selected items
      final List<String> displayTexts = [];

      for (final value in selectedValues) {
        // Find the corresponding dropdown item to get its display widget
        final item = items.firstWhere(
          (item) => item.value == value,
          orElse: () => DropdownMenuItem<T>(
            value: value,
            child: Text(value.toString()),
          ),
        );

        // Extract the display text
        String displayText = '';
        if (item.child is _DropdownItemWithDescription) {
          final enhancedItem = item.child as _DropdownItemWithDescription;
          if (enhancedItem.title is Text) {
            displayText = (enhancedItem.title as Text).data ?? value.toString();
          }
        } else if (item.child is Text) {
          displayText = (item.child as Text).data ?? value.toString();
        } else {
          displayText = value.toString();
        }

        displayTexts.add(displayText);
      }

      // Join them with commas for display
      final String displayValue = displayTexts.join(', ');

      return Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          Expanded(
            child: Text(
              displayValue,
              overflow: TextOverflow.ellipsis,
            ),
          ),
          const Icon(Icons.arrow_drop_down),
        ],
      );
    }

    return FormField<Set<T>>(
      initialValue: selectedValues,
      validator: validator,
      builder: (state) {
        return InkWell(
          onTap: () async {
            // Show a modal with our desired semi-opaque background
            final result = await showDialog<Set<T>>(
              context: state.context,
              barrierDismissible: true,
              barrierColor: Colors.transparent,
              builder: (context) {
                // Create a working copy of the selected values
                final ValueNotifier<Set<T>> workingSet =
                    ValueNotifier<Set<T>>(Set<T>.from(selectedValues));

                // Add a search controller if there are more than 8 items
                final bool showSearch = items.length > 8;
                final TextEditingController searchController =
                    TextEditingController();
                final ValueNotifier<List<DropdownMenuItem<T>>> filteredItems =
                    ValueNotifier<List<DropdownMenuItem<T>>>(items);

                // Helper function to try to extract searchable text from a widget
                String getSearchableText(Widget? widget) {
                  if (widget == null) return '';
                  if (widget is Text) {
                    return widget.data ?? '';
                  }
                  if (widget is RichText) {
                    // Simplified approach for RichText
                    return widget.text.toPlainText();
                  }
                  // For other types, we can't extract text reliably
                  return '';
                }

                // Function to filter items based on search text
                void filterItems(String query) {
                  if (query.isEmpty) {
                    filteredItems.value = items;
                    return;
                  }

                  final String searchQuery = query.toLowerCase();
                  filteredItems.value = items.where((item) {
                    if (item.child is _DropdownItemWithDescription) {
                      final enhancedItem =
                          item.child as _DropdownItemWithDescription;

                      // Extract text from title and use description
                      final titleText =
                          getSearchableText(enhancedItem.title).toLowerCase();
                      final descText = enhancedItem.description.toLowerCase();

                      return titleText.contains(searchQuery) ||
                          descText.contains(searchQuery);
                    } else {
                      // Try to extract text from the child widget
                      final itemText =
                          getSearchableText(item.child).toLowerCase();
                      return itemText.contains(searchQuery);
                    }
                  }).toList();
                }

                return BackdropFilter(
                  filter: ImageFilter.blur(sigmaX: 8, sigmaY: 8),
                  child: Container(
                    color: AppTheme.black.withAlpha(200),
                    child: Dialog(
                      // Adjust alignment to top when search is visible
                      alignment:
                          showSearch ? Alignment.topCenter : Alignment.center,
                      insetPadding: EdgeInsets.only(
                          left: 40,
                          right: 40,
                          // Less padding at top when search is visible
                          top: showSearch ? 60 : 24,
                          bottom: 24),
                      child: ConstrainedBox(
                        constraints: BoxConstraints(
                          maxWidth: 500,
                          maxHeight: MediaQuery.of(context).size.height * 0.7,
                        ),
                        child: Column(
                          mainAxisSize: MainAxisSize.min,
                          crossAxisAlignment: CrossAxisAlignment.stretch,
                          children: [
                            // Header with Save/Cancel buttons
                            Container(
                              padding: const EdgeInsets.symmetric(
                                  vertical: 12, horizontal: 16),
                              child: Row(
                                  mainAxisAlignment:
                                      MainAxisAlignment.spaceBetween,
                                  children: [
                                    Text(
                                      'Select options',
                                      style: TextStyle(
                                        fontWeight: FontWeight.bold,
                                        color: AppColors.primary,
                                      ),
                                    ),
                                    Row(
                                      children: [
                                        TextButton(
                                          onPressed: () {
                                            Navigator.of(context)
                                                .pop(); // Close dialog without selection
                                          },
                                          style: TextButton.styleFrom(
                                              padding:
                                                  const EdgeInsets.symmetric(
                                                      horizontal: 8,
                                                      vertical: 4),
                                              minimumSize: const Size(0, 0),
                                              tapTargetSize:
                                                  MaterialTapTargetSize
                                                      .shrinkWrap,
                                              foregroundColor: AppColors.error,
                                              backgroundColor: AppColors.error
                                                  .withAlpha(20)),
                                          child: const Text('Cancel'),
                                        ),
                                        const SizedBox(width: 8),
                                        TextButton(
                                          onPressed: () {
                                            Navigator.of(context)
                                                .pop(workingSet.value);
                                          },
                                          style: TextButton.styleFrom(
                                              padding:
                                                  const EdgeInsets.symmetric(
                                                      horizontal: 8,
                                                      vertical: 4),
                                              minimumSize: const Size(0, 0),
                                              tapTargetSize:
                                                  MaterialTapTargetSize
                                                      .shrinkWrap,
                                              foregroundColor:
                                                  AppColors.primary,
                                              backgroundColor: AppColors.primary
                                                  .withAlpha(20)),
                                          child: const Text('Apply'),
                                        ),
                                      ],
                                    ),
                                  ]),
                            ),

                            // Divider after header
                            Divider(
                                height: 1,
                                color: AppColors.primary.withAlpha(60)),

                            // Search bar if needed
                            if (showSearch)
                              Container(
                                padding: const EdgeInsets.symmetric(
                                    horizontal: 16, vertical: 8),
                                child: TextField(
                                  controller: searchController,
                                  decoration: InputDecoration(
                                    hintText: 'Search...',
                                    prefixIcon: const Icon(Icons.search),
                                    contentPadding: const EdgeInsets.symmetric(
                                        vertical: 8, horizontal: 12),
                                    border: OutlineInputBorder(
                                      borderRadius: BorderRadius.circular(8),
                                    ),
                                  ),
                                  onChanged: filterItems,
                                ),
                              ),

                            // List of items - wrapped in Expanded to avoid intrinsic sizing issues
                            Flexible(
                              child: ValueListenableBuilder<
                                  List<DropdownMenuItem<T>>>(
                                valueListenable: filteredItems,
                                builder: (context, currentItems, _) {
                                  if (currentItems.isEmpty &&
                                      searchController.text.isNotEmpty) {
                                    return Center(
                                      child: Padding(
                                        padding: const EdgeInsets.all(16),
                                        child: Text(
                                          "No matching options found",
                                          textAlign: TextAlign.center,
                                          style: TextStyle(
                                            color: AppTheme.grey,
                                            fontStyle: FontStyle.italic,
                                          ),
                                        ),
                                      ),
                                    );
                                  }

                                  return ValueListenableBuilder<Set<T>>(
                                    valueListenable: workingSet,
                                    builder: (context, currentSelection, _) {
                                      return ListView.separated(
                                        shrinkWrap: true,
                                        separatorBuilder: (context, index) =>
                                            Divider(
                                          height: 1,
                                          color: AppTheme.grey.withAlpha(60),
                                          indent: 16,
                                          endIndent: 16,
                                        ),
                                        itemCount: currentItems.length,
                                        itemBuilder: (context, index) {
                                          final item = currentItems[index];
                                          final bool isSelected =
                                              currentSelection
                                                  .contains(item.value);

                                          // Check if this item can be deselected
                                          bool canToggle = true;
                                          if (isSelected &&
                                              canDeselect != null) {
                                            canToggle =
                                                canDeselect(item.value as T);
                                          }

                                          // Function to toggle selection
                                          void toggleSelection() {
                                            if (isSelected) {
                                              if (canToggle) {
                                                workingSet.value = Set<T>.from(
                                                    currentSelection)
                                                  ..remove(item.value as T);
                                              }
                                            } else {
                                              workingSet.value =
                                                  Set<T>.from(currentSelection)
                                                    ..add(item.value as T);
                                            }
                                          }

                                          // Check if this item has a description
                                          if (item.child
                                              is _DropdownItemWithDescription) {
                                            // Extract the title and description
                                            final enhancedItem = item.child
                                                as _DropdownItemWithDescription;

                                            // Return a list tile with both title and subtitle
                                            return ListTile(
                                              contentPadding:
                                                  const EdgeInsets.symmetric(
                                                      horizontal: 16,
                                                      vertical: 8),
                                              title: enhancedItem.title,
                                              subtitle: Text(
                                                enhancedItem.description,
                                                style: TextStyle(
                                                  fontSize: 12,
                                                  color: isSelected
                                                      ? AppColors.primary
                                                      : AppTheme.white
                                                          .withAlpha(120),
                                                ),
                                              ),
                                              selected: isSelected,
                                              tileColor: isSelected
                                                  ? AppColors.primary
                                                      .withAlpha(20)
                                                  : null,
                                              onTap: canToggle
                                                  ? toggleSelection
                                                  : null,
                                              // Add a checkbox for multi-select
                                              leading: Checkbox(
                                                value: isSelected,
                                                onChanged: canToggle
                                                    ? (_) => toggleSelection()
                                                    : null,
                                                activeColor: AppColors.primary,
                                              ),
                                            );
                                          } else {
                                            // Regular item without description
                                            return ListTile(
                                              contentPadding:
                                                  const EdgeInsets.symmetric(
                                                      horizontal: 16,
                                                      vertical: 8),
                                              title: item.child,
                                              selected: isSelected,
                                              tileColor: isSelected
                                                  ? AppColors.primary
                                                      .withAlpha(20)
                                                  : null,
                                              onTap: canToggle
                                                  ? toggleSelection
                                                  : null,
                                              // Add a checkbox for multi-select
                                              leading: Checkbox(
                                                value: isSelected,
                                                onChanged: canToggle
                                                    ? (_) => toggleSelection()
                                                    : null,
                                                activeColor: AppColors.primary,
                                              ),
                                            );
                                          }
                                        },
                                      );
                                    },
                                  );
                                },
                              ),
                            ),
                          ],
                        ),
                      ),
                    ),
                  ),
                );
              },
            );

            // If user applied selections, update the form field
            if (result != null) {
              state.didChange(result);
              onChanged(result);
            }
          },
          child: InputDecorator(
            decoration: (decoration ?? const InputDecoration()).copyWith(
              errorText: state.hasError ? state.errorText : null,
            ),
            child: _buildDisplay(),
          ),
        );
      },
    );
  }
}

//----------------------------------------------------------------------------
// DROPDOWN COMPONENT CLASSES
//----------------------------------------------------------------------------

/// A widget that combines a title with a description
/// Used internally for enhanced dropdown items
class _DropdownItemWithDescription extends StatelessWidget {
  final Widget title;
  final String description;

  const _DropdownItemWithDescription({
    required this.title,
    required this.description,
  });

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        title,
        Text(
          description,
          style: const TextStyle(
            fontSize: 12,
            color: AppTheme.grey,
          ),
        ),
      ],
    );
  }
}

/// A widget that combines a title with a description
/// Used internally for enhanced dropdown items
class DropdownItemWithDescription extends StatelessWidget {
  final Widget title;
  final String description;

  const DropdownItemWithDescription({
    super.key,
    required this.title,
    required this.description,
  });

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        title,
        Text(
          description,
          style: const TextStyle(
            fontSize: 12,
            color: AppTheme.grey,
          ),
        ),
      ],
    );
  }
}
