import re from typing import Optional from datatypes.magicplan.api.response import PlanSummary _UK_POSTCODE_RE = re.compile(r"[A-Z]{1,2}\d[A-Z\d]?\s*\d[A-Z]{2}", re.IGNORECASE) def _extract_postcode(address: str) -> str | None: match = _UK_POSTCODE_RE.search(address) if match is None: return None return match.group().replace(" ", "").upper() def _normalize_postcode(postcode: str) -> str: return postcode.replace(" ", "").upper() def find_matching_plan(plans: list[PlanSummary], address: str) -> Optional[PlanSummary]: postcode = _extract_postcode(address) if postcode is None: return None address_lower = address.lower() for plan in plans: if plan.address is None: continue plan_postcode = plan.address.postal_code if plan_postcode is None: continue if _normalize_postcode(plan_postcode) != postcode: continue street_parts = [ p for p in [plan.address.street_number, plan.address.street] if p ] plan_street = " ".join(street_parts).lower() if plan_street and plan_street in address_lower: return plan return None