"""Camie vocabulary -> human-readable tag-name normalization.

Camie v2's ~57k tag vocabulary is booru-derived and arrives as raw
strings like `uchiha_sasuke_(naruto)`, `#unicus_(idolmaster)`,
`1000-nen_ikiteru_(vocaloid)`, or `:/`. We want the operator to see
"Uchiha Sasuke", "Unicus", "1000-Nen Ikiteru", or to never see the
emoticon at all — and we want the same clean string to be what lands
in `tag.name` when the suggestion is accepted, so Accept matches the
existing-tag convention (`tag_service.find_or_create`).

Rules (operator-approved 2026-06-03):
  1. Strip leading junk chars (#, ., +, ;, ~, _, whitespace)
  2. Drop trailing `_(disambiguator)` block(s), iteratively
  3. Strip wrapping single/double quotes (after disambig removal so
     `"foo_em_up"_(series)` -> `"foo_em_up"` -> `foo_em_up`)
  4. Replace remaining `_` with space; collapse runs of whitespace
  5. Add a space after any `:` (namespace:tag -> namespace: tag)
  6. Preserve hyphens (booru hyphens often carry meaning)
  7. Title-case each space-separated word (first character only —
     apostrophes, digits, hyphens stay)
  8. If no letters AND no digits remain, return None (drops emoticons
     like `:/` or `^_^`; preserves bare digit tags like `2005`)
  9. No surname/givenname swap — no reliable signal in the vocab
"""

import re

_LEADING_JUNK = re.compile(r"^[#.+;~_\s]+")
_TRAILING_DISAMBIG = re.compile(r"_\([^)]*\)\s*$")
_MULTISPACE = re.compile(r"\s+")
_COLON_NOSPACE = re.compile(r":(?=\S)")
_HAS_ALPHANUMERIC = re.compile(r"[A-Za-z0-9]")


def _strip_wrapping_quotes(s: str) -> str:
    if len(s) >= 2 and s[0] == s[-1] and s[0] in ('"', "'"):
        return s[1:-1]
    return s


def _title_word(w: str) -> str:
    return w[:1].upper() + w[1:] if w else w


def normalize(raw: str) -> str | None:
    """Return the human-readable form of a raw Camie tag, or None if the
    string is junk (emoticon, empty after stripping)."""
    if not raw:
        return None
    s = _LEADING_JUNK.sub("", raw)
    while True:
        new = _TRAILING_DISAMBIG.sub("", s)
        if new == s:
            break
        s = new
    s = _strip_wrapping_quotes(s)
    s = s.replace("_", " ")
    s = _COLON_NOSPACE.sub(": ", s)
    s = _MULTISPACE.sub(" ", s).strip()
    if not s or not _HAS_ALPHANUMERIC.search(s):
        return None
    return " ".join(_title_word(w) for w in s.split(" "))
