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});

/// 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;

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

  @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 {
    final result = await showModalBottomSheet<Object?>(
      context: context,
      isScrollControlled: true,
      useSafeArea: true,
      builder: (sheetContext) {
        var query = '';

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

            return SizedBox(
              height: MediaQuery.of(context).size.height * 0.85,
              child: Column(
                children: [
                  Padding(
                    padding: const EdgeInsets.fromLTRB(16, 12, 16, 8),
                    child: Row(
                      children: [
                        Expanded(
                          child: Text(
                            label,
                            style: Theme.of(context).textTheme.titleMedium,
                          ),
                        ),
                        TextButton.icon(
                          onPressed: () =>
                              Navigator.pop(context, _clearSelectionToken),
                          icon: const Icon(Icons.clear),
                          label: const Text('Rensa'),
                        ),
                      ],
                    ),
                  ),
                  Padding(
                    padding: const EdgeInsets.fromLTRB(16, 0, 16, 8),
                    child: TextField(
                      autofocus: true,
                      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: (context, 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(context, product.id),
                              );
                            },
                          ),
                  ),
                ],
              ),
            );
          },
        );
      },
    );

    if (!context.mounted) return;
    if (result == null) {
      return;
    }
    if (result == _clearSelectionToken) {
      onChanged?.call(null);
      return;
    }
    if (result is int) {
      onChanged?.call(result);
    }
  }
}
