"""Shared lookup tables used by both the dedup-side normalizers and the
display-side format standardizer.

Both modules need the same authoritative mapping of US state names →
2-letter postal codes and USPS street-suffix abbreviations. Keeping a
single source of truth avoids the bug-class where the two layers drift
("Drive" → "Dr" in one but "Drv" in the other).

Per-module aliases (``_US_STATE_NAMES_NORM`` lowercase-only for matching
keys vs. ``_US_STATE_NAMES`` casefold-on-lookup for display) are still
defined locally to preserve historical behavior; both derive from the
canonical maps below.
"""

from __future__ import annotations

# US state name (lowercase) → 2-letter postal code.
US_STATE_NAMES: dict[str, str] = {
    "alabama": "AL", "alaska": "AK", "arizona": "AZ", "arkansas": "AR",
    "california": "CA", "colorado": "CO", "connecticut": "CT",
    "delaware": "DE", "florida": "FL", "georgia": "GA", "hawaii": "HI",
    "idaho": "ID", "illinois": "IL", "indiana": "IN", "iowa": "IA",
    "kansas": "KS", "kentucky": "KY", "louisiana": "LA", "maine": "ME",
    "maryland": "MD", "massachusetts": "MA", "michigan": "MI",
    "minnesota": "MN", "mississippi": "MS", "missouri": "MO",
    "montana": "MT", "nebraska": "NE", "nevada": "NV",
    "new hampshire": "NH", "new jersey": "NJ", "new mexico": "NM",
    "new york": "NY", "north carolina": "NC", "north dakota": "ND",
    "ohio": "OH", "oklahoma": "OK", "oregon": "OR", "pennsylvania": "PA",
    "rhode island": "RI", "south carolina": "SC", "south dakota": "SD",
    "tennessee": "TN", "texas": "TX", "utah": "UT", "vermont": "VT",
    "virginia": "VA", "washington": "WA", "west virginia": "WV",
    "wisconsin": "WI", "wyoming": "WY",
    "district of columbia": "DC",
}

# 2-letter US state postal codes (incl. territories). The placeholder
# code "ST" appears in the corpus fixtures; preserved here so the
# standardizer doesn't expand it as a Street abbreviation.
US_STATE_CODES: frozenset[str] = frozenset({
    "AL", "AK", "AZ", "AR", "CA", "CO", "CT", "DE", "FL", "GA",
    "HI", "ID", "IL", "IN", "IA", "KS", "KY", "LA", "ME", "MD",
    "MA", "MI", "MN", "MS", "MO", "MT", "NE", "NV", "NH", "NJ",
    "NM", "NY", "NC", "ND", "OH", "OK", "OR", "PA", "RI", "SC",
    "SD", "TN", "TX", "UT", "VT", "VA", "WA", "WV", "WI", "WY",
    "DC", "PR", "VI", "GU", "AS", "MP",
    "ST",
})

# Long-form → USPS-canonical short form (compression). Used by the
# format standardizer when ``expand=False`` and by normalize_address
# when reducing to a matching key.
USPS_COMPRESSIONS: dict[str, str] = {
    "street": "St", "avenue": "Ave", "boulevard": "Blvd",
    "drive": "Dr", "lane": "Ln", "road": "Rd", "court": "Ct",
    "place": "Pl", "circle": "Cir", "trail": "Trl", "terrace": "Ter",
    "parkway": "Pkwy", "highway": "Hwy", "expressway": "Expy",
    "freeway": "Fwy", "square": "Sq", "alley": "Aly",
    "crossing": "Xing", "point": "Pt",
    "north": "N", "south": "S", "east": "E", "west": "W",
    "northeast": "NE", "northwest": "NW", "southeast": "SE",
    "southwest": "SW",
    "apartment": "Apt", "suite": "Ste", "building": "Bldg",
    "floor": "Fl", "room": "Rm", "fort": "Ft", "mount": "Mt",
    "heights": "Hts", "springs": "Spgs",
}

# Canadian province + territory postal codes.
CA_PROVINCE_CODES: frozenset[str] = frozenset({
    "AB", "BC", "MB", "NB", "NL", "NS", "NT", "NU",
    "ON", "PE", "QC", "SK", "YT",
})

# Canadian province / territory name → 2-letter code.
CA_PROVINCE_NAMES: dict[str, str] = {
    "alberta": "AB", "british columbia": "BC", "manitoba": "MB",
    "new brunswick": "NB", "newfoundland and labrador": "NL",
    "newfoundland": "NL", "labrador": "NL", "nova scotia": "NS",
    "northwest territories": "NT", "nunavut": "NU", "ontario": "ON",
    "prince edward island": "PE", "quebec": "QC", "québec": "QC",
    "saskatchewan": "SK", "yukon": "YT",
}

# Australian state + territory postal abbreviations.
AU_STATE_CODES: frozenset[str] = frozenset({
    "NSW", "VIC", "QLD", "WA", "SA", "TAS", "ACT", "NT",
})
AU_STATE_NAMES: dict[str, str] = {
    "new south wales": "NSW", "victoria": "VIC", "queensland": "QLD",
    "western australia": "WA", "south australia": "SA",
    "tasmania": "TAS", "australian capital territory": "ACT",
    "northern territory": "NT",
}

# German Bundesland (state) postal abbreviations (per ISO 3166-2:DE).
DE_STATE_CODES: frozenset[str] = frozenset({
    "BW", "BY", "BE", "BB", "HB", "HH", "HE", "MV",
    "NI", "NW", "RP", "SL", "SN", "ST", "SH", "TH",
})
DE_STATE_NAMES: dict[str, str] = {
    "baden-württemberg": "BW", "baden-wurttemberg": "BW",
    "bayern": "BY", "bavaria": "BY",
    "berlin": "BE", "brandenburg": "BB",
    "bremen": "HB", "hamburg": "HH",
    "hessen": "HE", "hesse": "HE",
    "mecklenburg-vorpommern": "MV",
    "niedersachsen": "NI", "lower saxony": "NI",
    "nordrhein-westfalen": "NW", "north rhine-westphalia": "NW",
    "rheinland-pfalz": "RP", "rhineland-palatinate": "RP",
    "saarland": "SL",
    "sachsen": "SN", "saxony": "SN",
    "sachsen-anhalt": "ST", "saxony-anhalt": "ST",
    "schleswig-holstein": "SH",
    "thüringen": "TH", "thuringen": "TH", "thuringia": "TH",
}

# Postal-code patterns by country (used for shape detection in addresses).
# ``utf8`` flag suppressed: all patterns are pure ASCII at the structural
# level even when the surrounding address is unicode.
POSTAL_PATTERNS: dict[str, str] = {
    "us":  r"\b\d{5}(?:-\d{4})?\b",
    "ca":  r"\b[A-Z]\d[A-Z]\s*\d[A-Z]\d\b",
    # UK postcodes: outward (1-2 letters + 1-2 digits + optional letter)
    # then optional space then inward (digit + 2 letters). Real grammar
    # is more involved but this catches every shipping format.
    "uk":  r"\b[A-Z]{1,2}\d[A-Z\d]?\s*\d[A-Z]{2}\b",
    # German postal: 5 digits.
    "de":  r"\b\d{5}\b",
    # Australian postal: 4 digits.
    "au":  r"\b\d{4}\b",
    # French postal: 5 digits (covered by DE pattern but kept explicit).
    "fr":  r"\b\d{5}\b",
}

# International street-suffix expansions / compressions, keyed by language.
# Keys are casefold + period-stripped; values are the canonical form to
# emit. Empty for languages where USPS-style abbreviation isn't idiomatic
# (Japanese, Korean — addresses use full words and ideographic markers).
INTL_STREET_SUFFIXES: dict[str, dict[str, str]] = {
    "de": {
        # Long → short (e.g., for matching keys); the standardizer's
        # ``expand=False`` mode uses this set.
        "strasse": "Str", "straße": "Str", "str": "Straße",
        "platz": "Pl", "pl": "Platz",
        "weg": "W", "w": "Weg",
        "gasse": "G", "g": "Gasse",
    },
    "fr": {
        "rue": "R", "r": "Rue",
        "avenue": "Av", "av": "Avenue",
        "boulevard": "Bd", "bd": "Boulevard",
        "place": "Pl", "pl": "Place",
        "chemin": "Ch", "ch": "Chemin",
        "impasse": "Imp", "imp": "Impasse",
    },
    "es": {
        "calle": "C", "c": "Calle",
        "avenida": "Av", "av": "Avenida",
        "plaza": "Pza", "pza": "Plaza",
        "paseo": "P°", "carretera": "Ctra", "ctra": "Carretera",
    },
    "it": {
        "via": "V", "v": "Via",
        "viale": "V.le",
        "corso": "C.so",
        "piazza": "P.za", "pza": "Piazza",
    },
    "uk": {
        # UK uses the long form by default; "Cl"/"Mws" are uncommon.
        "cl": "Close", "mws": "Mews",
    },
}

# Localized "PO Box" patterns. Each value is a regex matching all
# variants of "PO Box" in that language. The standardizer folds matches
# to the canonical form passed in ``po_box_canonical``.
INTL_PO_BOX_PATTERNS: dict[str, str] = {
    "en": r"(?:p\.?\s*o\.?\s*box|post\s+office\s+box)",
    "de": r"(?:postfach|pf)\b",
    "fr": r"(?:bo[iî]te\s+postale|b\.?\s*p\.?)\b",
    "es": r"(?:apartado(?:\s+postal)?|apdo\.?)\b",
    "it": r"(?:casella\s+postale|c\.?\s*p\.?)\b",
    "pt": r"(?:caixa\s+postal|c\.?\s*p\.?)\b",
}

# Abbreviation → expansion (the inverse of USPS_COMPRESSIONS, plus a
# handful of legacy aliases like ``av`` → ``Avenue``). Used by the
# format standardizer when ``expand=True`` (default).
USPS_EXPANSIONS: dict[str, str] = {
    "st": "Street",
    "ave": "Avenue", "av": "Avenue",
    "blvd": "Boulevard", "blv": "Boulevard",
    "dr": "Drive",
    "ln": "Lane",
    "rd": "Road",
    "ct": "Court",
    "pl": "Place",
    "cir": "Circle",
    "trl": "Trail", "tr": "Trail",
    "ter": "Terrace",
    "pkwy": "Parkway",
    "hwy": "Highway",
    "expy": "Expressway",
    "fwy": "Freeway",
    "sq": "Square",
    "aly": "Alley",
    "xing": "Crossing",
    "pt": "Point",
    "n": "North", "s": "South", "e": "East", "w": "West",
    "ne": "Northeast", "nw": "Northwest",
    "se": "Southeast", "sw": "Southwest",
    "apt": "Apartment",
    "ste": "Suite",
    "bldg": "Building",
    "fl": "Floor",
    "rm": "Room",
    "ft": "Fort",
    "mt": "Mount",
    "hts": "Heights",
    "spgs": "Springs",
}
