import 'package:injectable/injectable.dart';
import 'package:superport/data/models/zipcode_dto.dart';
import 'package:superport/data/repositories/zipcode_repository.dart';

abstract class ZipcodeUseCase {
  /// 우편번호 검색 (페이지네이션 지원)
  Future<ZipcodeListResponse> searchZipcodes({
    int page = 1,
    int limit = 20,
    String? search,
    String? sido,
    String? gu,
  });

  /// 우편번호로 정확한 주소 조회
  Future<ZipcodeDto?> getZipcodeByNumber(int zipcode);

  /// 시도별 구 목록 조회
  Future<List<String>> getGuListBySido(String sido);

  /// 전체 시도 목록 조회
  Future<List<String>> getAllSidoList();

  /// 주소 문자열로 우편번호 검색 (최적화된 검색)
  Future<List<ZipcodeDto>> searchByAddress(String address);

  /// 우편번호 유효성 검사
  bool validateZipcode(int zipcode);

  /// 검색어 유효성 검사 및 정규화
  String normalizeSearchQuery(String query);
}

@Injectable(as: ZipcodeUseCase)
class ZipcodeUseCaseImpl implements ZipcodeUseCase {
  final ZipcodeRepository _repository;

  ZipcodeUseCaseImpl(this._repository);

  @override
  Future<ZipcodeListResponse> searchZipcodes({
    int page = 1,
    int limit = 20,
    String? search,
    String? sido,
    String? gu,
  }) async {
    // 비즈니스 로직: 페이지네이션 유효성 검사
    if (page < 1) page = 1;
    if (limit < 1 || limit > 100) limit = 20;

    // 검색어 정규화
    final normalizedSearch = search != null && search.isNotEmpty 
        ? normalizeSearchQuery(search) 
        : null;

    return await _repository.search(
      page: page,
      limit: limit,
      search: normalizedSearch,
      sido: sido?.trim(),
      gu: gu?.trim(),
    );
  }

  @override
  Future<ZipcodeDto?> getZipcodeByNumber(int zipcode) async {
    // 우편번호 유효성 검사
    if (!validateZipcode(zipcode)) {
      throw ArgumentError('유효하지 않은 우편번호입니다. (5자리 숫자)');
    }

    return await _repository.getByZipcode(zipcode);
  }

  @override
  Future<List<String>> getGuListBySido(String sido) async {
    if (sido.trim().isEmpty) {
      throw ArgumentError('시도명을 입력해주세요.');
    }

    final normalizedSido = sido.trim();
    return await _repository.getGuBySido(normalizedSido);
  }

  @override
  Future<List<String>> getAllSidoList() async {
    return await _repository.getAllSido();
  }

  @override
  Future<List<ZipcodeDto>> searchByAddress(String address) async {
    if (address.trim().isEmpty) {
      return [];
    }

    final normalizedAddress = normalizeSearchQuery(address);
    
    try {
      // 먼저 전체 검색으로 시도
      final response = await _repository.search(
        search: normalizedAddress,
        limit: 10, // 상위 10개만 가져오기
      );
      
      return response.items;
    } catch (e) {
      // 검색 실패 시 빈 목록 반환
      return [];
    }
  }

  @override
  bool validateZipcode(int zipcode) {
    // 한국 우편번호는 5자리 숫자 (00000 ~ 99999)
    return zipcode >= 0 && zipcode <= 99999;
  }

  @override
  String normalizeSearchQuery(String query) {
    if (query.trim().isEmpty) return '';

    String normalized = query.trim();
    
    // 공백 정규화 (여러 공백을 하나로)
    normalized = normalized.replaceAll(RegExp(r'\s+'), ' ');
    
    // 특수문자 제거 (단, 한글, 영문, 숫자, 공백, 하이픈만 유지)
    normalized = normalized.replaceAll(RegExp(r'[^\w\s가-힣ㄱ-ㅎㅏ-ㅣ-]'), '');
    
    return normalized;
  }


}