
from typing import Any, Dict, Optional


def get_nested(d: dict, *path, default=None) -> Any:
    cur = d
    for k in path:
        if cur is None or not isinstance(cur, dict):
            return default
        cur = cur.get(k)
    return cur if cur is not None else default


def to_float(x) -> Optional[float]:
    try:
        if x in (None, "", "NA"):
            return None
        return float(x)
    except Exception:
        return None


def to_int(x) -> Optional[int]:
    try:
        if x in (None, "", "NA"):
            return None
        return int(round(float(x)))
    except Exception:
        return None


def first_key(d: Dict[str, Any], *keys) -> Any:
    if not isinstance(d, dict):
        return None
    for k in keys:
        if k in d:
            return d[k]
    return None


def get_attr(d: Dict[str, Any], *cands) -> Any:
    if not isinstance(d, dict):
        return None
    for k in cands:
        if k in d:
            return d[k]
    return None


def get_attr_loose(d: Dict[str, Any], field_no_at: str) -> Any:
    return get_attr(d, f"@{field_no_at}", f"@_{field_no_at}", field_no_at)


def normalize_street_no_trailing_comma(s: str) -> str:
    if not s:
        return ""
    for tag in (" Unit ", " UNIT ", " Apt ", " APT ", "#"):
        if tag in s:
            s = s.split(tag)[0].strip()
    return s.strip()
