import 'package:injectable/injectable.dart'; import 'package:superport/core/constants/app_constants.dart'; import 'package:superport/data/models/zipcode_dto.dart'; import 'package:superport/data/repositories/zipcode_repository.dart'; abstract class ZipcodeUseCase { /// 우편번호 검색 (페이지네이션 지원) Future searchZipcodes({ int page = 1, int limit = AppConstants.defaultPageSize, String? search, String? sido, String? gu, }); /// 검색어 유효성 검사 및 정규화 String normalizeSearchQuery(String query); /// Hierarchy API - 시도 목록 조회 Future getHierarchySidos(); /// Hierarchy API - 구/군 목록 조회 Future getHierarchyGusBySido(String sido); } @Injectable(as: ZipcodeUseCase) class ZipcodeUseCaseImpl implements ZipcodeUseCase { final ZipcodeRepository _repository; ZipcodeUseCaseImpl(this._repository); @override Future searchZipcodes({ int page = 1, int limit = AppConstants.defaultPageSize, String? search, String? sido, String? gu, }) async { // 비즈니스 로직: 페이지네이션 유효성 검사 if (page < 1) page = 1; if (limit < 1 || limit > 100) limit = AppConstants.defaultPageSize; // 검색어 정규화 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 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; } @override Future getHierarchySidos() async { return await _repository.getHierarchySidos(); } @override Future getHierarchyGusBySido(String sido) async { if (sido.trim().isEmpty) { throw ArgumentError('시도명을 입력해주세요.'); } return await _repository.getHierarchyGusBySido(sido.trim()); } }