"""Core name normalization pipeline."""

import logging
import re

from unidecode import unidecode

from corp_names.data.nicknames import NICKNAME_TO_CANONICAL
from corp_names.data.prefixes import PREFIXES
from corp_names.data.suffixes import SUFFIXES
from corp_names.models import NormalizedName

log = logging.getLogger(__name__)


def normalize_name(name: str) -> NormalizedName:
    """Normalize a person name: strip titles, suffixes, middle initials, resolve nicknames."""
    original = name

    # Unicode normalize
    name = unidecode(name)

    # Strip punctuation: remove periods and commas, preserve hyphens, collapse whitespace
    name = name.replace(".", " ").replace(",", " ")
    name = re.sub(r"\s+", " ", name).strip()

    # Tokenize
    tokens = name.split()

    # Strip prefixes (scan left)
    prefixes_found: list[str] = []
    while tokens:
        candidate = tokens[0].lower()
        if candidate in PREFIXES:
            prefixes_found.append(candidate)
            tokens = tokens[1:]
        # Check two-word prefixes
        elif len(tokens) >= 2 and f"{candidate} {tokens[1].lower()}" in PREFIXES:
            prefixes_found.append(f"{candidate} {tokens[1].lower()}")
            tokens = tokens[2:]
        else:
            break

    # Strip suffixes (scan right)
    suffixes_found: list[str] = []
    while tokens:
        candidate = tokens[-1].lower()
        if candidate in SUFFIXES:
            suffixes_found.append(candidate)
            tokens = tokens[:-1]
        else:
            break

    # Remove middle initials (single-letter tokens, but not first or last)
    if len(tokens) > 2:
        tokens = [tokens[0]] + [t for t in tokens[1:-1] if len(t) > 1] + [tokens[-1]]

    # Extract first/last
    first = tokens[0].lower() if tokens else ""
    last = tokens[-1].lower() if len(tokens) > 1 else ""

    # Resolve nicknames
    nickname_resolved = False
    canonical_first = NICKNAME_TO_CANONICAL.get(first)
    if canonical_first:
        first = canonical_first
        nickname_resolved = True

    # Build normalized form
    name_tokens = [first] + [t.lower() for t in tokens[1:]] if tokens else []
    if nickname_resolved and name_tokens:
        name_tokens[0] = first
    normalized = " ".join(name_tokens)

    prefix_str = " ".join(prefixes_found)
    suffix_str = " ".join(reversed(suffixes_found))

    return NormalizedName(
        original=original,
        normalized=normalized,
        first=first,
        last=last,
        prefix=prefix_str,
        suffix=suffix_str,
        nickname_resolved=nickname_resolved,
    )
