import 'package:flutter/material.dart';

/// Typ för att hantera förändringar av värden.
typedef ValueChanged<T> = void Function(T value);

/// A named record representing a selectable product option.
typedef ProductOption = ({int id, String name, int? categoryId});

/// A form field that opens a searchable bottom sheet for selecting a product.
///
/// Replaces a long [DropdownButtonFormField] when the product list is large.
/// Works both inside and outside a [Form].
class ProductPickerField extends StatelessWidget {
  static const _clearSelectionToken = '__clear_selection__';

  final List<ProductOption> products;

  /// Currently selected product id, or null if nothing is selected.
  final int? value;

  /// Called when the user picks a product.
  final ValueChanged<int?>? onChanged;

  /// Whether the field is interactive.
  final bool enabled;

  /// Shows a loading spinner inside the field while products are being fetched.
  final bool isLoading;

  /// Label shown in the field border.
  final String label;

  /// Inline error message shown below the field.
  final String? errorText;

  /// If set, the picker bottom sheet opens with this text pre-filled in the search field.
  final String? initialQuery;

  const ProductPickerField({
    super.key,
    required this.products,
    this.value,
    this.onChanged,
    this.enabled = true,
    this.isLoading = false,
    this.label = 'Produkt',
    this.errorText,
    this.initialQuery,
  });

  @override
  Widget build(BuildContext context) {
    final selected = value == null
        ? null
        : products.cast<ProductOption?>().firstWhere(
              (p) => p?.id == value,
              orElse: () => null,
            );

    final interactive = enabled && !isLoading && products.isNotEmpty;

    return MouseRegion(
      cursor: interactive ? SystemMouseCursors.click : MouseCursor.defer,
      child: GestureDetector(
        onTap: interactive ? () => _openPicker(context) : null,
        child: InputDecorator(
          decoration: InputDecoration(
            labelText: label,
            errorText: errorText,
            border: const OutlineInputBorder(),
          ),
          child: isLoading
              ? const Padding(
                  padding: EdgeInsets.all(12),
                  child: SizedBox(
                    width: 20,
                    height: 20,
                    child: CircularProgressIndicator(strokeWidth: 2),
                  ),
                )
              : selected == null
                  ? Text(
                      products.isEmpty
                          ? 'Inga produkter tillgängliga'
                          : 'Tryck för att välja produkt',
                    )
                  : Text(selected.name),
        ),
      ),
    );
  }

  Future<void> _openPicker(BuildContext context) async {
    // Skapa controller utanför showSheet för att undvika reset vid rebuild
    final result = await ProductPickerField.showSheet(
      context,
      products: products,
      value: value,
      label: label,
      initialQuery: initialQuery,
    );
    if (!context.mounted) return;
    if (result == null) return;
    if (result == _clearSelectionToken) {
      onChanged?.call(null);
      return;
    }
    if (result is int) onChanged?.call(result);
  }

  /// Öppnar produktväljarens bottenark utan att binda den till en specifik widget-instans.
  /// Returnerar valt produkt-id, null (ingen ändring), eller [_clearSelectionToken] (rensa).
  ///
  /// [categoryFilter] — om satt visas bara produkter vars categoryId finns i listan.
  /// [onCreate] — valfri callback för att skapa en ny produkt; anropas med produktnamnet
  ///   och returnerar den nya `ProductOption` om skapandet lyckades.
  static Future<int?> showSheet(
    BuildContext context, {
    required List<ProductOption> products,
    int? value,
    String label = 'Produkt',
    String? initialQuery,
    Set<int>? categoryFilter,
    Future<ProductOption?> Function(String name)? onCreate,
  }) async {
    // Filtrera på kategori om angiven, men visa alla om filtret ger nollresultat
    final baseList = categoryFilter != null && categoryFilter.isNotEmpty
        ? products.where((p) => p.categoryId != null && categoryFilter.contains(p.categoryId)).toList()
        : products;
    final useList = baseList.isNotEmpty ? baseList : products;

    final result = await showModalBottomSheet<Object?>(
      context: context,
      isScrollControlled: true,
      useSafeArea: true,
      builder: (sheetContext) {
        final controller = TextEditingController(text: initialQuery ?? '');
        var query = initialQuery ?? '';
        // Mutable lokal kopia — nya produkter kan läggas till
        var displayList = useList.toList();

        return StatefulBuilder(
          builder: (ctx, setModalState) {
            final normalizedQuery = query.trim().toLowerCase();
            final filtered = normalizedQuery.isEmpty
                ? displayList
                : displayList
                    .where((p) => p.name.toLowerCase().contains(normalizedQuery))
                    .toList();

            final isFiltered = displayList.length < products.length;

            // "Skapa ny produkt"-dialog
            Future<void> openCreateDialog() async {
              final nameCtrl = TextEditingController(text: query.trim());
              final confirmed = await showDialog<bool>(
                context: ctx,
                builder: (dCtx) => AlertDialog(
                  title: const Text('Ny produkt'),
                  content: TextField(
                    controller: nameCtrl,
                    autofocus: true,
                    textCapitalization: TextCapitalization.sentences,
                    decoration: const InputDecoration(
                      labelText: 'Produktnamn',
                      border: OutlineInputBorder(),
                    ),
                  ),
                  actions: [
                    TextButton(
                      onPressed: () => Navigator.pop(dCtx, false),
                      child: const Text('Avbryt'),
                    ),
                    FilledButton(
                      onPressed: () => Navigator.pop(dCtx, true),
                      child: const Text('Skapa'),
                    ),
                  ],
                ),
              );
              if (confirmed != true || !ctx.mounted) return;
              final newProduct = await onCreate!(nameCtrl.text);
              if (newProduct == null || !ctx.mounted) return;
              setModalState(() => displayList = [...displayList, newProduct]);
              if (ctx.mounted) Navigator.pop(ctx, newProduct.id);
            }

            return SizedBox(
              height: MediaQuery.of(ctx).size.height * 0.85,
              child: Column(
                children: [
                  Padding(
                    padding: const EdgeInsets.fromLTRB(16, 12, 16, 8),
                    child: Row(
                      children: [
                        Expanded(
                          child: Column(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                              Text(label, style: Theme.of(ctx).textTheme.titleMedium),
                              if (isFiltered)
                                Text(
                                  'Visar ${displayList.length} produkter i föreslagen kategori',
                                  style: Theme.of(ctx).textTheme.labelSmall?.copyWith(color: Colors.green.shade700),
                                ),
                            ],
                          ),
                        ),
                        if (onCreate != null)
                          TextButton.icon(
                            onPressed: openCreateDialog,
                            icon: const Icon(Icons.add),
                            label: const Text('Skapa ny'),
                          ),
                        TextButton.icon(
                          onPressed: () => Navigator.pop(ctx, _clearSelectionToken),
                          icon: const Icon(Icons.clear),
                          label: const Text('Rensa'),
                        ),
                      ],
                    ),
                  ),
                  Padding(
                    padding: const EdgeInsets.fromLTRB(16, 0, 16, 8),
                    child: TextField(
                      autofocus: true,
                      controller: controller,
                      decoration: const InputDecoration(
                        hintText: 'Sök produkt...',
                        prefixIcon: Icon(Icons.search),
                        border: OutlineInputBorder(),
                      ),
                      onChanged: (text) => setModalState(() => query = text),
                    ),
                  ),
                  const Divider(height: 1),
                  Expanded(
                    child: filtered.isEmpty
                        ? const Center(child: Text('Inga produkter matchar sökningen.'))
                        : ListView.separated(
                            itemCount: filtered.length,
                            separatorBuilder: (_, __) => const Divider(height: 1),
                            itemBuilder: (ctx2, index) {
                              final product = filtered[index];
                              final isSelected = product.id == value;
                              return ListTile(
                                selected: isSelected,
                                title: Text(product.name),
                                trailing: isSelected ? const Icon(Icons.check) : null,
                                onTap: () => Navigator.pop(ctx2, product.id),
                              );
                            },
                          ),
                  ),
                ],
              ),
            );
          },
        );
      },
    );

    if (result == null || result == _clearSelectionToken) return null;
    if (result is int) return result;
    return null;
  }
}
