"""BibTeX key generation — deterministic, normalized keys.

Format: {first_author_surname}{year}{first_significant_title_word}
Example: smith2024deep

Rules:
    - Surname extracted from first author
    - Unicode normalized (diacritics stripped)
    - Stopwords skipped in title
    - All lowercase, alphanumeric only
"""

from __future__ import annotations

import re
import unicodedata

__all__ = ["generate_key"]

# English stopwords to skip in title
_STOPWORDS = frozenset(
    {
        "a",
        "an",
        "the",
        "of",
        "in",
        "for",
        "and",
        "or",
        "to",
        "on",
        "at",
        "by",
        "with",
        "from",
        "is",
        "are",
        "was",
        "were",
        "be",
        "been",
        "being",
        "has",
        "have",
        "had",
        "do",
        "does",
        "did",
        "but",
        "not",
        "so",
        "if",
        "as",
        "it",
        "its",
        "no",
        "nor",
        "than",
        "that",
        "this",
        "what",
        "when",
        "where",
        "which",
        "who",
        "whom",
        "how",
        "via",
        "using",
        "towards",
        "toward",
    }
)

# Name suffixes to strip
_SUFFIXES = frozenset(
    {
        "jr",
        "jr.",
        "sr",
        "sr.",
        "ii",
        "iii",
        "iv",
        "phd",
        "md",
    }
)


def generate_key(authors: list[str], year: int | None, title: str) -> str:
    """Generate a deterministic BibTeX citation key.

    Args:
        authors: List of author names (various formats supported).
        year: Publication year (omitted from key if None).
        title: Paper title.

    Returns:
        Lowercase alphanumeric key like "smith2024deep".
    """
    surname = _normalize_surname(authors[0]) if authors else "unknown"
    word = _first_significant_word(title)
    year_str = str(year) if year is not None else ""
    return f"{surname}{year_str}{word}"


def _normalize_surname(name: str) -> str:
    """Extract and normalize the surname from an author name.

    Handles formats:
        - "John Smith" → "smith"
        - "Smith, John" → "smith"
        - "Jean-Pierre Dupont" → "dupont"
        - "José García" → "garcia"
        - "Smith Jr." → "smith"
        - "O'Brien" → "obrien"
    """
    name = name.strip()

    # Handle "Surname, Given" format
    if "," in name:
        surname = name.split(",")[0].strip()
    else:
        # "Given Surname" format — take last part
        parts = name.split()
        # Filter out suffixes
        parts = [p for p in parts if p.lower().rstrip(".") not in _SUFFIXES]
        surname = parts[-1] if parts else name

    # Strip diacritics via NFD decomposition
    surname = _strip_diacritics(surname)

    # Keep only ASCII letters
    surname = re.sub(r"[^a-zA-Z]", "", surname)

    return surname.lower()


def _strip_diacritics(text: str) -> str:
    """Remove diacritical marks from unicode text.

    "Müller" → "Muller", "García" → "Garcia"
    """
    nfkd = unicodedata.normalize("NFKD", text)
    return "".join(c for c in nfkd if not unicodedata.combining(c))


def _first_significant_word(title: str) -> str:
    """Extract the first non-stopword from a title.

    Skips common English stopwords. Falls back to "untitled"
    if title is empty or contains only stopwords.
    """
    if not title.strip():
        return "untitled"

    # Split on non-alphanumeric (handles hyphens, colons, etc.)
    words = re.findall(r"[a-zA-Z]+", _strip_diacritics(title))

    for word in words:
        if word.lower() not in _STOPWORDS:
            return str(word).lower()

    return "untitled"
