import 'package:flutter/material.dart';

typedef ItemBuilder<T> = String Function(T item);
typedef FetchItems<T> = Future<List<T>> Function({int page, String search});

class DropdownSearch<T> extends StatefulWidget {
  final FetchItems<T> fetchItems;
  final ItemBuilder<T> itemLabel;
  final Function(T) onSelected;
  final String hintText;
  final int pageSize;

  const DropdownSearch({
    super.key,
    required this.fetchItems,
    required this.itemLabel,
    required this.onSelected,
    this.hintText = 'Select',
    this.pageSize = 20,
  });

  @override
  State<DropdownSearch<T>> createState() => _DropdownSearchState<T>();
}

class _DropdownSearchState<T> extends State<DropdownSearch<T>> {
  final TextEditingController searchController = TextEditingController();
  final ScrollController scrollController = ScrollController();

  List<T> items = [];
  T? selectedItem;
  int currentPage = 1;
  bool isLoading = false;
  bool hasMore = true;
  bool isDropdownOpen = false;

  @override
  void initState() {
    super.initState();
    _fetchItems(reset: true);

    scrollController.addListener(() {
      if (scrollController.position.pixels >= scrollController.position.maxScrollExtent - 50) {
        if (!isLoading && hasMore) {
          _fetchItems();
        }
      }
    });
  }

  Future<void> _fetchItems({bool reset = false}) async {
    if (isLoading) return;

    if (reset) {
      currentPage = 1;
      items.clear();
      hasMore = true;
    }

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

    List<T> newItems = await widget.fetchItems(
      page: currentPage,
      search: searchController.text,
    );

    if (newItems.length < widget.pageSize) {
      hasMore = false;
    }

    items.addAll(newItems);
    currentPage++;
    setState(() {
      isLoading = false;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        GestureDetector(
          onTap: () {
            setState(() {
              isDropdownOpen = !isDropdownOpen;
            });
          },
          child: Container(
            padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 7),
            decoration: BoxDecoration(
              border: Border.all(color: Colors.grey.shade400),
              borderRadius: BorderRadius.circular(8),
            ),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                Text(
                  selectedItem != null ? widget.itemLabel(selectedItem as T) : widget.hintText,
                  style: const TextStyle(fontSize: 16),
                ),
                Icon(isDropdownOpen ? Icons.arrow_drop_up : Icons.arrow_drop_down),
              ],
            ),
          ),
        ),
        if (isDropdownOpen)
          Column(
            children: [
              const SizedBox(height: 8),
              TextField(
                controller: searchController,
                decoration: const InputDecoration(
                  prefixIcon: Icon(Icons.search),
                  hintText: 'Search...',
                ),
                onChanged: (value) => _fetchItems(reset: true),
              ),
              const SizedBox(height: 8),
              Container(
                height: 250,
                decoration: BoxDecoration(
                  border: Border.all(color: Colors.grey.shade400),
                  borderRadius: BorderRadius.circular(8),
                ),
                child: ListView.builder(
                  controller: scrollController,
                  itemCount: items.length + (hasMore ? 1 : 0),
                  itemBuilder: (context, index) {
                    if (index == items.length) {
                      return const Padding(
                        padding: EdgeInsets.all(8.0),
                        child: Center(child: CircularProgressIndicator()),
                      );
                    }

                    T item = items[index];
                    return ListTile(
                      title: Text(widget.itemLabel(item)),
                      selected: selectedItem == item,
                      onTap: () {
                        setState(() {
                          selectedItem = item;
                          isDropdownOpen = false;
                        });
                        widget.onSelected(item);
                      },
                    );
                  },
                ),
              ),
            ],
          ),
      ],
    );
  }
}
