import 'package:flutter/material.dart';
import 'base_field.dart';
import '../../../shared/widgets/inputs/modern_text_field.dart';

class AutocompleteMultiSelectField extends BaseField {
  final String fieldKey;
  final String label;
  final String hint;
  final bool isRequired;
  final Future<List<Map<String, dynamic>>> Function() optionsLoader;
  final String valueKey;
  final String displayKey;

  AutocompleteMultiSelectField({
    required this.fieldKey,
    required this.label,
    required this.hint,
    required this.optionsLoader,
    required this.valueKey,
    required this.displayKey,
    this.isRequired = false,
  })  : assert(valueKey != ''),
        assert(displayKey != '');

  @override
  String? Function(String?)? get validator => (value) {
        if (isRequired && (value == null || value.isEmpty)) {
          return '$label is required';
        }
        return null;
      };

  @override
  Widget buildField({
    required TextEditingController controller,
    required ColorScheme colorScheme,
    VoidCallback? onChanged,
  }) {
    return _AutocompleteMultiSelectWidget(
      fieldKey: fieldKey,
      label: label,
      hint: hint,
      isRequired: isRequired,
      optionsLoader: optionsLoader,
      valueKey: valueKey,
      displayKey: displayKey,
      controller: controller,
      colorScheme: colorScheme,
      onChanged: onChanged,
      validator: validator,
    );
  }
}

class _AutocompleteMultiSelectWidget extends StatefulWidget {
  final String fieldKey;
  final String label;
  final String hint;
  final bool isRequired;
  final Future<List<Map<String, dynamic>>> Function() optionsLoader;
  final String valueKey;
  final String displayKey;
  final TextEditingController controller;
  final ColorScheme colorScheme;
  final VoidCallback? onChanged;
  final String? Function(String?)? validator;

  const _AutocompleteMultiSelectWidget({
    required this.fieldKey,
    required this.label,
    required this.hint,
    required this.isRequired,
    required this.optionsLoader,
    required this.valueKey,
    required this.displayKey,
    required this.controller,
    required this.colorScheme,
    required this.onChanged,
    required this.validator,
  });

  @override
  State<_AutocompleteMultiSelectWidget> createState() =>
      _AutocompleteMultiSelectWidgetState();
}

class _AutocompleteMultiSelectWidgetState
    extends State<_AutocompleteMultiSelectWidget> {
  List<Map<String, dynamic>>? _cachedOptions;
  bool _isLoading = false;
  bool _hasLoaded = false;

  @override
  String? Function(String?)? get validator => (value) {
        if (widget.isRequired && (value == null || value.isEmpty)) {
          return '${widget.label} is required';
        }
        return null;
      };

  @override
  Map<String, dynamic>? get customProperties => {
        'isMultiSelect': true,
        'valueKey': widget.valueKey,
        'displayKey': widget.displayKey,
      };

  Future<void> _loadOptions() async {
    if (_hasLoaded || _isLoading) return;

    setState(() {
      _isLoading = true;
    });

    try {
      final options = await widget.optionsLoader();
      if (mounted) {
        setState(() {
          _cachedOptions = options;
          _isLoading = false;
          _hasLoaded = true;
        });
      }
    } catch (e) {
      if (mounted) {
        setState(() {
          _isLoading = false;
        });
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    // Load options when widget is first built
    if (!_hasLoaded && !_isLoading) {
      _loadOptions();
    }

    final List<Map<String, dynamic>> options = _cachedOptions ?? const [];

    // Get display options for autocomplete
    final Iterable<String> displayOptions = options
        .map((e) => e[widget.displayKey])
        .where((e) => e != null)
        .map((e) => e.toString());

    // Parse selected values (stored as comma-separated IDs)
    final Set<String> selectedIds = widget.controller.text.isEmpty
        ? <String>{}
        : widget.controller.text
            .split(',')
            .map((e) => e.trim())
            .where((e) => e.isNotEmpty)
            .toSet();

    // Get selected display values for chips
    final Set<String> selectedDisplays = selectedIds
        .map((id) {
          final match = options.firstWhere(
            (o) => (o[widget.valueKey]?.toString() ?? '') == id,
            orElse: () => const {},
          );
          return match.isNotEmpty
              ? (match[widget.displayKey]?.toString() ?? '')
              : '';
        })
        .where((display) => display.isNotEmpty)
        .toSet();

    void toggleSelection(String displayValue) {
      // Find the corresponding ID for this display value
      final match = options.firstWhere(
        (o) => (o[widget.displayKey]?.toString() ?? '') == displayValue,
        orElse: () => const {},
      );

      if (match.isNotEmpty) {
        final id = match[widget.valueKey]?.toString() ?? '';
        if (selectedIds.contains(id)) {
          selectedIds.remove(id);
        } else {
          selectedIds.add(id);
        }
        widget.controller.text = selectedIds.join(',');
        widget.onChanged?.call();
      }
    }

    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Autocomplete<String>(
          optionsBuilder: (TextEditingValue tev) {
            if (tev.text.isEmpty) return const Iterable<String>.empty();
            return displayOptions.where(
                (opt) => opt.toLowerCase().contains(tev.text.toLowerCase()));
          },
          onSelected: (String selection) => toggleSelection(selection),
          fieldViewBuilder:
              (context, textController, focusNode, onFieldSubmitted) {
            return ModernTextField(
              label: widget.label,
              hint: widget.hint,
              controller: textController,
              focusNode: focusNode,
              onSubmitted: (_) {
                final v = textController.text.trim();
                if (v.isNotEmpty) {
                  // Check if the entered text matches any display option
                  final match = displayOptions.firstWhere(
                    (opt) => opt.toLowerCase() == v.toLowerCase(),
                    orElse: () => '',
                  );
                  if (match.isNotEmpty) {
                    toggleSelection(match);
                    textController.clear();
                  }
                }
              },
              suffixIcon: textController.text.isNotEmpty
                  ? IconButton(
                      icon: const Icon(Icons.clear),
                      onPressed: () {
                        textController.clear();
                        widget.onChanged?.call();
                      },
                    )
                  : const Icon(Icons.search),
              onChanged: (_) => widget.onChanged?.call(),
            );
          },
          optionsViewBuilder: (context, onSelected, optionsIt) {
            final list = optionsIt.toList();
            return Align(
              alignment: Alignment.topLeft,
              child: Material(
                elevation: 6,
                color: widget.colorScheme.surface,
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(12),
                  side: BorderSide(
                      color: widget.colorScheme.outline.withOpacity(0.15)),
                ),
                child: ConstrainedBox(
                  constraints:
                      const BoxConstraints(maxHeight: 280, minWidth: 240),
                  child: list.isEmpty
                      ? Padding(
                          padding: const EdgeInsets.all(16),
                          child: Row(
                            children: [
                              Icon(Icons.info_outline,
                                  color: widget.colorScheme.onSurfaceVariant),
                              const SizedBox(width: 8),
                              Expanded(
                                child: Text(
                                  'No results',
                                  style: TextStyle(
                                      color:
                                          widget.colorScheme.onSurfaceVariant),
                                ),
                              ),
                            ],
                          ),
                        )
                      : ListView.separated(
                          shrinkWrap: true,
                          padding: const EdgeInsets.symmetric(vertical: 8),
                          itemCount: list.length,
                          separatorBuilder: (_, __) => Divider(
                              height: 1,
                              color:
                                  widget.colorScheme.outline.withOpacity(0.08)),
                          itemBuilder: (context, index) {
                            final opt = list[index];
                            return ListTile(
                              title: Text(opt),
                              onTap: () {
                                onSelected(opt);
                              },
                            );
                          },
                        ),
                ),
              ),
            );
          },
        ),
        const SizedBox(height: 8),
        Wrap(
          spacing: 8,
          children: selectedDisplays
              .map((displayValue) => Chip(
                    label: Text(displayValue),
                    onDeleted: () => toggleSelection(displayValue),
                  ))
              .toList(),
        ),
        if (_isLoading)
          const Padding(
            padding: EdgeInsets.only(top: 8.0),
            child: LinearProgressIndicator(minHeight: 2),
          ),
        if (widget.validator != null)
          Builder(
            builder: (context) {
              final error = widget.validator!(widget.controller.text);
              return error != null
                  ? Padding(
                      padding: const EdgeInsets.only(top: 6),
                      child: Text(error,
                          style: TextStyle(
                              color: widget.colorScheme.error, fontSize: 12)),
                    )
                  : const SizedBox.shrink();
            },
          )
      ],
    );
  }
}
