"""New Mexico — SOS SOS portal automation. Name search implemented via the public business entity search. LLC/Corp filing selectors pending live portal verification. """ from __future__ import annotations import re from scripts.formation.base import ( StatePortal, NameSearchResult, FormationOrder, FilingResult, FilingStatus, ) from .config import CONFIG class NMPortal(StatePortal): STATE_CODE = "NM" STATE_NAME = "New Mexico" PORTAL_NAME = "SOS" PORTAL_URL = CONFIG["portal_url"] NWRA_ADDRESS = CONFIG["nwra_address"] NWRA_CITY = CONFIG["nwra_city"] NWRA_STATE = CONFIG["nwra_state"] NWRA_ZIP = CONFIG["nwra_zip"] async def search_name(self, name: str) -> NameSearchResult: """Search New Mexico business name availability via the public portal.""" try: page = await self.start_browser() await page.goto(CONFIG["name_search_url"], wait_until="networkidle") await self.human_delay(1.0, 2.5) search_sel = ( CONFIG["selectors"].get("search_input") or 'input[type="text"], input[name*="earch"], input[name*="ame"]' ) await page.fill(search_sel, "") await self.type_slowly(page, search_sel, name) await self.human_delay(0.5, 1.0) btn_sel = ( CONFIG["selectors"].get("search_button") or 'button[type="submit"], input[type="submit"]' ) await page.click(btn_sel) await page.wait_for_load_state("networkidle") await self.human_delay(1.0, 2.0) content = await page.content() await self.screenshot(page, f"${CODE}_name_search_{name}") no_results = any( phrase in content.lower() for phrase in ["no match", "no results", "no records", "no entities", "0 results"] ) if no_results: return NameSearchResult( available=True, exact_match=False, similar_names=[], state_code="NM", searched_name=name, raw_response=content[:2000], ) similar: list[str] = [] pattern = re.compile(r']*>([^<]*?' + re.escape(name[:8]) + r'[^<]*?)', re.IGNORECASE) for m in pattern.finditer(content): found = m.group(1).strip() if found and 3 < len(found) < 200: similar.append(found) exact = any( s.upper().replace(",", "").strip() == name.upper().replace(",", "").strip() for s in similar ) return NameSearchResult( available=not exact, exact_match=exact, similar_names=similar[:10], state_code="NM", searched_name=name, raw_response=content[:2000], ) except Exception as exc: return NameSearchResult( available=False, state_code="NM", searched_name=name, raw_response=f"Error: {exc}", ) async def file_llc(self, order: FormationOrder) -> FilingResult: """File an LLC in New Mexico. Selectors pending live portal verification.""" return FilingResult( success=False, status=FilingStatus.PENDING, state_code="NM", entity_name=order.entity_name, error_message=( "NM filing adapter selectors pending verification. " f"Admin: file manually at {CONFIG['portal_url']} — LLC formation." ), ) async def file_corporation(self, order: FormationOrder) -> FilingResult: """File a corporation in New Mexico. Selectors pending live portal verification.""" return FilingResult( success=False, status=FilingStatus.PENDING, state_code="NM", entity_name=order.entity_name, error_message=( "NM filing adapter selectors pending verification. " f"Admin: file manually at {CONFIG['portal_url']} — Corp formation." ), ) def adapter() -> NMPortal: return NMPortal()