import 'package:flutter/material.dart';

/// Lightweight, bounds-safe multi-select picker used in dialogs.
/// - Renders chips for selected items and a `Select` ActionChip.
/// - Opens a root dialog with search + select-all + checkbox list.
class MultiSelectPicker<T> extends StatefulWidget {
  const MultiSelectPicker({
    super.key,
    required this.label,
    required this.items,
    required this.selectedIds,
    required this.getId,
    required this.getLabel,
    required this.onChanged,
  });

  final String label;
  final List<T> items;
  final List<String> selectedIds;
  final String Function(T) getId;
  final String Function(T) getLabel;
  final ValueChanged<List<String>> onChanged;

  @override
  State<MultiSelectPicker<T>> createState() => _MultiSelectPickerState<T>();
}

class _MultiSelectPickerState<T> extends State<MultiSelectPicker<T>> {
  late List<String> _selectedIds;
  String _search = '';

  @override
  void initState() {
    super.initState();
    _selectedIds = List<String>.from(widget.selectedIds);
  }

  Future<void> _openPicker() async {
    final screenWidth = MediaQuery.of(context).size.width;
    final isMobile = screenWidth <= 600;
    const double kPickerMaxWidth = 720;

    List<String>? result;

    if (isMobile) {
      result = await showModalBottomSheet<List<String>>(
        context: context,
        isScrollControlled: true,
        builder: (sheetContext) {
          List<String> working = List<String>.from(_selectedIds);
          bool workingSelectAll =
              working.length == widget.items.length && widget.items.isNotEmpty;
          String localSearch = _search;

          return StatefulBuilder(
            builder: (sheetContext, setState) {
              final filtered = widget.items
                  .where(
                    (item) => widget
                        .getLabel(item)
                        .toLowerCase()
                        .contains(localSearch.toLowerCase()),
                  )
                  .toList();

              return SafeArea(
                child: Padding(
                  padding: EdgeInsets.only(
                    left: 16,
                    right: 16,
                    top: 12,
                    bottom: MediaQuery.of(sheetContext).viewInsets.bottom + 12,
                  ),
                  child: Column(
                    mainAxisSize: MainAxisSize.min,
                    children: [
                      Text(
                        'Select ${widget.label}',
                        style: Theme.of(sheetContext).textTheme.titleLarge,
                      ),
                      const SizedBox(height: 8),
                      TextField(
                        decoration: const InputDecoration(
                          hintText: 'Search...',
                        ),
                        onChanged: (v) => setState(() => localSearch = v),
                      ),
                      CheckboxListTile(
                        value: workingSelectAll,
                        title: const Text('Select All'),
                        onChanged: (checked) {
                          setState(() {
                            workingSelectAll = checked ?? false;
                            if (workingSelectAll) {
                              working = widget.items.map(widget.getId).toList();
                            } else {
                              working = [];
                            }
                          });
                        },
                      ),
                      SizedBox(
                        height: 320,
                        child: ListView(
                          children: [
                            for (final item in filtered)
                              CheckboxListTile(
                                value: working.contains(widget.getId(item)),
                                title: Text(widget.getLabel(item)),
                                onChanged: (checked) {
                                  setState(() {
                                    final id = widget.getId(item);
                                    if (checked == true) {
                                      working.add(id);
                                    } else {
                                      working.remove(id);
                                    }
                                    workingSelectAll =
                                        working.length == widget.items.length &&
                                        widget.items.isNotEmpty;
                                  });
                                },
                              ),
                          ],
                        ),
                      ),
                      Row(
                        mainAxisAlignment: MainAxisAlignment.end,
                        children: [
                          TextButton(
                            onPressed: () => Navigator.of(sheetContext).pop(),
                            child: const Text('Cancel'),
                          ),
                          const SizedBox(width: 8),
                          ElevatedButton(
                            onPressed: () =>
                                Navigator.of(sheetContext).pop(working),
                            child: const Text('Done'),
                          ),
                        ],
                      ),
                    ],
                  ),
                ),
              );
            },
          );
        },
      );
    } else {
      result = await showDialog<List<String>>(
        context: context,
        useRootNavigator: true,
        builder: (dialogContext) {
          List<String> working = List<String>.from(_selectedIds);
          bool workingSelectAll =
              working.length == widget.items.length && widget.items.isNotEmpty;
          String localSearch = _search;

          return Center(
            child: ConstrainedBox(
              constraints: const BoxConstraints(maxWidth: kPickerMaxWidth),
              child: StatefulBuilder(
                builder: (dialogContext, setState) {
                  final filtered = widget.items
                      .where(
                        (item) => widget
                            .getLabel(item)
                            .toLowerCase()
                            .contains(localSearch.toLowerCase()),
                      )
                      .toList();

                  return AlertDialog(
                    title: Text('Select ${widget.label}'),
                    content: Column(
                      mainAxisSize: MainAxisSize.min,
                      children: [
                        TextField(
                          decoration: const InputDecoration(
                            hintText: 'Search...',
                          ),
                          onChanged: (v) => setState(() => localSearch = v),
                        ),
                        CheckboxListTile(
                          value: workingSelectAll,
                          title: const Text('Select All'),
                          onChanged: (checked) {
                            setState(() {
                              workingSelectAll = checked ?? false;
                              if (workingSelectAll) {
                                working = widget.items
                                    .map(widget.getId)
                                    .toList();
                              } else {
                                working = [];
                              }
                            });
                          },
                        ),
                        SizedBox(
                          height: 220,
                          width: double.maxFinite,
                          child: ListView(
                            children: [
                              for (final item in filtered)
                                CheckboxListTile(
                                  value: working.contains(widget.getId(item)),
                                  title: Text(widget.getLabel(item)),
                                  onChanged: (checked) {
                                    setState(() {
                                      final id = widget.getId(item);
                                      if (checked == true) {
                                        working.add(id);
                                      } else {
                                        working.remove(id);
                                      }
                                      workingSelectAll =
                                          working.length ==
                                              widget.items.length &&
                                          widget.items.isNotEmpty;
                                    });
                                  },
                                ),
                            ],
                          ),
                        ),
                      ],
                    ),
                    actions: [
                      TextButton(
                        onPressed: () => Navigator.of(dialogContext).pop(),
                        child: const Text('Cancel'),
                      ),
                      ElevatedButton(
                        onPressed: () =>
                            Navigator.of(dialogContext).pop(working),
                        child: const Text('Done'),
                      ),
                    ],
                  );
                },
              ),
            ),
          );
        },
      );
    }

    if (result is List<String>) {
      setState(() {
        _selectedIds = List<String>.from(result!);
        _search = '';
      });
      widget.onChanged(_selectedIds);
    }
  }

  @override
  void didUpdateWidget(covariant MultiSelectPicker<T> oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (oldWidget.selectedIds != widget.selectedIds) {
      _selectedIds = List<String>.from(widget.selectedIds);
    }
  }

  @override
  Widget build(BuildContext context) {
    // Avoid using LayoutBuilder inside InputDecorator because AlertDialog (and
    // other parents) may request intrinsic dimensions which causes LayoutBuilder
    // to throw. Use a MediaQuery-based maxWidth instead — it is intrinsic-safe.
    final double screenMaxWidth = MediaQuery.of(context).size.width - 48.0;

    return InputDecorator(
      decoration: InputDecoration(labelText: widget.label),
      child: ConstrainedBox(
        constraints: BoxConstraints(maxWidth: screenMaxWidth),
        child: Align(
          alignment: Alignment.centerLeft,
          child: Wrap(
            spacing: 8,
            runSpacing: 4,
            children: [
              for (final id in _selectedIds)
                Builder(
                  builder: (context) {
                    final item = widget.items.firstWhere(
                      (e) => widget.getId(e) == id,
                      orElse: () => null as T,
                    );
                    if (item == null) return const SizedBox.shrink();
                    return Chip(
                      label: Text(widget.getLabel(item)),
                      onDeleted: () {
                        setState(() {
                          _selectedIds.remove(id);
                        });
                        widget.onChanged(_selectedIds);
                      },
                    );
                  },
                ),
              ActionChip(
                label: const Text('Select'),
                avatar: const Icon(Icons.arrow_drop_down),
                onPressed: _openPicker,
              ),
            ],
          ),
        ),
      ),
    );
  }
}
