import 'dart:async';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart';
import 'package:shadcn_ui/shadcn_ui.dart';

import 'package:superport_v2/features/masters/customer/domain/entities/customer.dart';
import 'package:superport_v2/features/masters/customer/domain/repositories/customer_repository.dart';

/// 고객 검색 결과 모델.
class InventoryCustomerOption {
  InventoryCustomerOption({
    required this.id,
    required this.code,
    required this.name,
    required this.industry,
    required this.region,
  });

  factory InventoryCustomerOption.fromCustomer(Customer customer) {
    return InventoryCustomerOption(
      id: customer.id ?? 0,
      code: customer.customerCode,
      name: customer.customerName,
      industry: customer.note ?? '-',
      region: customer.zipcode?.sido ?? '-',
    );
  }

  final int id;
  final String code;
  final String name;
  final String industry;
  final String region;

  @override
  String toString() => '$name ($code)';
}

/// 여러 고객을 원격 검색으로 선택하는 필드.
class InventoryCustomerMultiSelectField extends StatefulWidget {
  const InventoryCustomerMultiSelectField({
    super.key,
    this.initialCustomerIds = const <int>{},
    required this.onChanged,
    this.enabled = true,
    this.placeholder,
  });

  final Set<int> initialCustomerIds;
  final ValueChanged<List<InventoryCustomerOption>> onChanged;
  final bool enabled;
  final Widget? placeholder;

  @override
  State<InventoryCustomerMultiSelectField> createState() =>
      _InventoryCustomerMultiSelectFieldState();
}

class _InventoryCustomerMultiSelectFieldState
    extends State<InventoryCustomerMultiSelectField> {
  static const Duration _debounceDuration = Duration(milliseconds: 300);

  final ShadSelectController<int> _controller = ShadSelectController<int>(
    initialValue: <int>{},
  );
  final Map<int, InventoryCustomerOption> _selectedOptions = {};
  final List<InventoryCustomerOption> _suggestions = [];
  Timer? _debounce;
  int _requestId = 0;
  bool _isSearching = false;
  String _searchKeyword = '';

  CustomerRepository? get _repository =>
      GetIt.I.isRegistered<CustomerRepository>()
      ? GetIt.I<CustomerRepository>()
      : null;

  @override
  void initState() {
    super.initState();
    if (widget.initialCustomerIds.isNotEmpty) {
      _controller.value = widget.initialCustomerIds.toSet();
      _prefetchInitialOptions(widget.initialCustomerIds);
    }
  }

  Future<void> _prefetchInitialOptions(Set<int> ids) async {
    final repository = _repository;
    if (repository == null) {
      return;
    }
    for (final id in ids) {
      try {
        final detail = await repository.fetchDetail(id, includeZipcode: false);
        _selectedOptions[id] = InventoryCustomerOption.fromCustomer(detail);
      } catch (_) {
        // 무시하고 다음 ID로 진행한다.
      }
    }
    _notifySelection();
    setState(() {});
  }

  void _scheduleSearch(String keyword) {
    _debounce?.cancel();
    _debounce = Timer(_debounceDuration, () => _search(keyword));
  }

  Future<void> _search(String keyword) async {
    final repository = _repository;
    if (repository == null) {
      return;
    }
    final request = ++_requestId;
    setState(() {
      _isSearching = true;
    });
    try {
      final result = await repository.list(
        page: 1,
        pageSize: 20,
        query: keyword.isEmpty ? null : keyword,
        isActive: true,
      );
      if (!mounted || request != _requestId) {
        return;
      }
      setState(() {
        _suggestions
          ..clear()
          ..addAll(result.items.map(InventoryCustomerOption.fromCustomer));
        _isSearching = false;
      });
    } catch (_) {
      if (!mounted || request != _requestId) {
        return;
      }
      setState(() {
        _suggestions.clear();
        _isSearching = false;
      });
    }
  }

  void _notifySelection() {
    widget.onChanged(_selectedOptions.values.toList(growable: false));
  }

  @override
  void dispose() {
    _controller.dispose();
    _debounce?.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final placeholder = widget.placeholder ?? const Text('고객사 선택');
    final selector = ShadSelect<int>.multipleWithSearch(
      controller: _controller,
      placeholder: placeholder,
      searchPlaceholder: const Text('고객사 이름 또는 코드 검색'),
      searchInputLeading: const Icon(LucideIcons.search, size: 16),
      clearSearchOnClose: false,
      closeOnSelect: false,
      onChanged: (values) {
        final sanitized = values.where((value) => value >= 0).toSet();
        if (!setEquals(sanitized, values)) {
          _controller.value = sanitized;
        }
        // 선택된 값이 deselect 되었을 때 map에서 제거한다.
        _selectedOptions.removeWhere((key, _) => !sanitized.contains(key));
        for (final value in sanitized) {
          final existing = _selectedOptions[value];
          if (existing != null) {
            continue;
          }
          final match = _suggestions.firstWhere(
            (option) => option.id == value,
            orElse: () => InventoryCustomerOption(
              id: value,
              code: 'ID-$value',
              name: '고객 $value',
              industry: '-',
              region: '-',
            ),
          );
          _selectedOptions[value] = match;
        }
        _notifySelection();
        setState(() {});
      },
      onSearchChanged: (keyword) {
        setState(() {
          _searchKeyword = keyword;
        });
        _scheduleSearch(keyword);
      },
      selectedOptionsBuilder: (context, values) {
        if (values.isEmpty) {
          return const Text('선택된 고객사가 없습니다');
        }
        return Wrap(
          spacing: 8,
          runSpacing: 8,
          children: [
            for (final value in values)
              ShadBadge(
                child: Padding(
                  padding: const EdgeInsets.symmetric(
                    horizontal: 8,
                    vertical: 4,
                  ),
                  child: Text(_selectedOptions[value]?.name ?? '고객 $value'),
                ),
              ),
          ],
        );
      },
      options: [
        if (_isSearching)
          const ShadOption(
            value: -1,
            child: Row(
              children: [
                SizedBox(
                  width: 16,
                  height: 16,
                  child: CircularProgressIndicator(strokeWidth: 2),
                ),
                SizedBox(width: 12),
                Text('검색 중...'),
              ],
            ),
          ),
        for (final option in _suggestions)
          ShadOption(
            value: option.id,
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(option.name),
                const SizedBox(height: 2),
                Text(
                  '${option.code} · ${option.industry} · ${option.region}',
                  style: const TextStyle(fontSize: 12, color: Colors.grey),
                ),
              ],
            ),
          ),
        if (!_isSearching && _suggestions.isEmpty && _searchKeyword.isNotEmpty)
          const ShadOption(value: -2, child: Text('검색 결과가 없습니다.')),
      ],
    );
    if (!widget.enabled) {
      return Opacity(
        opacity: 0.6,
        child: IgnorePointer(ignoring: true, child: selector),
      );
    }
    return selector;
  }
}
