import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:injectable/injectable.dart';
import 'package:superport/data/models/zipcode_dto.dart';
import 'package:superport/domain/usecases/zipcode_usecase.dart';
import 'package:superport/utils/constants.dart';

@injectable
class ZipcodeController extends ChangeNotifier {
  final ZipcodeUseCase _zipcodeUseCase;
  
  ZipcodeController(this._zipcodeUseCase);

  // 상태 변수들
  List<ZipcodeDto> _zipcodes = [];
  ZipcodeDto? _selectedZipcode;
  bool _isLoading = false;
  String? _errorMessage;
  
  // 페이지네이션
  int _currentPage = 1;
  int _totalPages = 1;
  int _totalCount = 0;
  final int _pageSize = PaginationConstants.defaultPageSize;
  
  // 검색 및 필터
  String _searchQuery = '';
  String? _selectedSido;
  String? _selectedGu;
  
  // 시도/구 목록 캐시
  List<String> _sidoList = [];
  List<String> _guList = [];
  
  // 디바운스를 위한 타이머
  Timer? _debounceTimer;
  
  // Getters
  List<ZipcodeDto> get zipcodes => _zipcodes;
  ZipcodeDto? get selectedZipcode => _selectedZipcode;
  bool get isLoading => _isLoading;
  String? get errorMessage => _errorMessage;
  int get currentPage => _currentPage;
  int get totalPages => _totalPages;
  int get totalCount => _totalCount;
  String get searchQuery => _searchQuery;
  String? get selectedSido => _selectedSido;
  String? get selectedGu => _selectedGu;
  List<String> get sidoList => _sidoList;
  List<String> get guList => _guList;
  bool get hasNextPage => _currentPage < _totalPages;
  bool get hasPreviousPage => _currentPage > 1;

  // 초기 데이터 로드
  Future<void> initialize() async {
    _isLoading = true;
    notifyListeners();
    
    // 시도 목록 로드
    await _loadSidoList();
    
    // 초기 우편번호 목록 로드 (첫 페이지)
    await searchZipcodes();
  }

  // 우편번호 검색
  Future<void> searchZipcodes({bool refresh = false}) async {
    if (refresh) {
      _currentPage = 1;
    }

    _setLoading(true);
    _clearError();

    try {
      final response = await _zipcodeUseCase.searchZipcodes(
        page: _currentPage,
        limit: _pageSize,
        search: _searchQuery.isNotEmpty ? _searchQuery : null,
        sido: _selectedSido,
        gu: _selectedGu,
      );

      _zipcodes = response.items;
      _totalCount = response.totalCount;
      _totalPages = response.totalPages;
      _currentPage = response.currentPage;
      
      notifyListeners();
    } catch (e) {
      _setError('우편번호 검색에 실패했습니다: ${e.toString()}');
    } finally {
      _setLoading(false);
    }
  }

  // 특정 우편번호로 정확한 주소 조회
  Future<void> getZipcodeByNumber(int zipcode) async {
    _setLoading(true);
    _clearError();

    try {
      _selectedZipcode = await _zipcodeUseCase.getZipcodeByNumber(zipcode);
      notifyListeners();
    } catch (e) {
      _setError('우편번호 조회에 실패했습니다: ${e.toString()}');
    } finally {
      _setLoading(false);
    }
  }

  // 주소로 우편번호 빠른 검색
  Future<List<ZipcodeDto>> quickSearchByAddress(String address) async {
    if (address.trim().isEmpty) return [];
    
    try {
      return await _zipcodeUseCase.searchByAddress(address);
    } catch (e) {
      return [];
    }
  }

  // 검색어 설정 (디바운스 적용)
  void setSearchQuery(String query) {
    _searchQuery = query;
    notifyListeners();
    
    // 디바운스 처리 (500ms 대기 후 검색 실행)
    _debounceTimer?.cancel();
    _debounceTimer = Timer(const Duration(milliseconds: 500), () {
      searchZipcodes(refresh: true);
    });
  }

  // 즉시 검색 실행 (디바운스 무시)
  Future<void> executeSearch() async {
    _debounceTimer?.cancel();
    _currentPage = 1;
    await searchZipcodes();
  }

  // 시도 선택
  Future<void> setSido(String? sido) async {
    _selectedSido = sido;
    _selectedGu = null; // 시도 변경 시 구 초기화
    _guList = []; // 구 목록 초기화
    notifyListeners();
    
    // 선택된 시도에 따른 구 목록 로드
    if (sido != null) {
      await _loadGuListBySido(sido);
    }
    
    // 검색 새로고침
    await searchZipcodes(refresh: true);
  }

  // 구 선택
  Future<void> setGu(String? gu) async {
    _selectedGu = gu;
    notifyListeners();
    
    // 검색 새로고침
    await searchZipcodes(refresh: true);
  }

  // 필터 초기화
  Future<void> clearFilters() async {
    _searchQuery = '';
    _selectedSido = null;
    _selectedGu = null;
    _guList = [];
    _currentPage = 1;
    notifyListeners();
    
    await searchZipcodes();
  }

  // 페이지 이동
  Future<void> goToPage(int page) async {
    if (page < 1 || page > _totalPages) return;
    
    _currentPage = page;
    await searchZipcodes();
  }

  // 다음 페이지
  Future<void> nextPage() async {
    if (hasNextPage) {
      await goToPage(_currentPage + 1);
    }
  }

  // 이전 페이지
  Future<void> previousPage() async {
    if (hasPreviousPage) {
      await goToPage(_currentPage - 1);
    }
  }

  // 시도 목록 로드 (캐시)
  Future<void> _loadSidoList() async {
    try {
      _sidoList = await _zipcodeUseCase.getAllSidoList();
    } catch (e) {
      debugPrint('시도 목록 로드 실패: $e');
      _sidoList = [];
    }
  }

  // 선택된 시도의 구 목록 로드
  Future<void> _loadGuListBySido(String sido) async {
    try {
      _guList = await _zipcodeUseCase.getGuListBySido(sido);
      notifyListeners();
    } catch (e) {
      debugPrint('구 목록 로드 실패: $e');
      _guList = [];
    }
  }

  // 우편번호 선택
  void selectZipcode(ZipcodeDto zipcode) {
    _selectedZipcode = zipcode;
    notifyListeners();
  }

  // 선택 초기화
  void clearSelection() {
    _selectedZipcode = null;
    notifyListeners();
  }

  // 내부 헬퍼 메서드
  void _setLoading(bool loading) {
    _isLoading = loading;
    notifyListeners();
  }

  void _setError(String message) {
    _errorMessage = message;
    notifyListeners();
  }

  void _clearError() {
    _errorMessage = null;
  }

  @override
  void dispose() {
    _debounceTimer?.cancel();
    _zipcodes = [];
    _selectedZipcode = null;
    super.dispose();
  }
}