from __future__ import annotations from typing import TYPE_CHECKING, Optional from backend.utils.addressMatch import AddressMatch from datatypes.epc.domain.epc_property_data import EpcPropertyData from datatypes.epc.search import EpcSearchResult if TYPE_CHECKING: from backend.epc_client.epc_client_service import EpcClientService _MIN_MATCH_SCORE = 0.6 def find_best_epc_match( service: EpcClientService, postcode: str, address: str, ) -> Optional[EpcPropertyData]: candidates = service.search_by_postcode(postcode) if not candidates: return None cert_num = _pick_best_cert(candidates, address, use_full_address=False) if cert_num: return _safe_get(service, cert_num) cert_num = _pick_best_cert(candidates, address, use_full_address=True) if cert_num: return _safe_get(service, cert_num) return None def _pick_best_cert( candidates: list[EpcSearchResult], user_address: str, use_full_address: bool, ) -> Optional[str]: scored: list[tuple[float, str]] = [ ( AddressMatch.score( user_address, r.full_address if use_full_address else r.address_line_1, ), r.certificate_number, ) for r in candidates ] if not scored: return None best_score = max(s for s, _ in scored) if best_score < _MIN_MATCH_SCORE: return None top = [cert for s, cert in scored if s == best_score] if len(top) != 1: return None return top[0] def _safe_get(service: EpcClientService, cert_num: str) -> Optional[EpcPropertyData]: from backend.epc_client.exceptions import EpcNotFoundError try: return service.get_by_certificate_number(cert_num) except EpcNotFoundError: return None