"""Master data for Polri ranks ('pangkat').

Used by the validation layer to:
1. Confirm that a recognized rank string is a real Polri rank.
2. Normalize abbreviated forms ("AKP" → "AKP", "Brigadir Polisi" → "Brigadir") to a canonical form.

Source: Peraturan Kapolri tentang Pangkat (publicly available, 2024).
Update this file when ranks are reorganized.
"""

from __future__ import annotations

# Canonical abbreviation → list of accepted variants (case-insensitive).
PANGKAT_VARIANTS: dict[str, tuple[str, ...]] = {
    # Tamtama
    "BHARADA": ("BHARADA", "BHRD"),
    "BHARATU": ("BHARATU", "BHRT"),
    "BHARAKA": ("BHARAKA", "BHRK"),
    "ABRIP": ("ABRIP",),
    "ABRIPTU": ("ABRIPTU",),
    "ABRIPKA": ("ABRIPKA",),
    # Bintara
    "BRIPDA": ("BRIPDA",),
    "BRIPTU": ("BRIPTU",),
    "BRIGADIR": ("BRIGADIR", "BRIG", "BRIG POL", "BRIGPOL"),
    "BRIPKA": ("BRIPKA",),
    "AIPDA": ("AIPDA",),
    "AIPTU": ("AIPTU",),
    # Perwira Pertama
    "IPDA": ("IPDA",),
    "IPTU": ("IPTU",),
    "AKP": ("AKP",),
    # Perwira Menengah
    "KOMPOL": ("KOMPOL",),
    "AKBP": ("AKBP",),
    "KOMBES POL": ("KOMBES POL", "KOMBESPOL", "KBP", "KOMBES"),
    # Perwira Tinggi
    "BRIGJEN POL": ("BRIGJEN POL", "BRIGJENPOL", "BRIGJEN"),
    "IRJEN POL": ("IRJEN POL", "IRJENPOL", "IRJEN"),
    "KOMJEN POL": ("KOMJEN POL", "KOMJENPOL", "KOMJEN"),
    "JENDERAL POL": ("JENDERAL POL", "JENDERALPOL", "JENDERAL"),
    # PNS Polri (Pegawai Negeri Sipil di lingkungan Polri). PNS appear
    # routinely on sprint panitia / undangan templates alongside Polri
    # personnel, so we treat them as valid ranks for extraction.
    # Sources: PP 11/2017 jo PP 17/2020 (Manajemen PNS); golongan I-IV.
    # Golongan I (Juru)
    "JURU MUDA": ("JURU MUDA",),
    "JURU MUDA TK I": ("JURU MUDA TK I", "JURU MUDA TK.I", "JURU MUDA TINGKAT I"),
    "JURU": ("JURU",),
    "JURU TK I": ("JURU TK I", "JURU TK.I", "JURU TINGKAT I"),
    # Golongan II (Pengatur)
    "PENGATUR MUDA": ("PENGATUR MUDA",),
    "PENGATUR MUDA TK I": (
        "PENGATUR MUDA TK I",
        "PENGATUR MUDA TK.I",
        "PENGATUR MUDA TINGKAT I",
    ),
    "PENGATUR": ("PENGATUR",),
    "PENGATUR TK I": ("PENGATUR TK I", "PENGATUR TK.I", "PENGATUR TINGKAT I"),
    # Golongan III (Penata)
    "PENATA MUDA": ("PENATA MUDA",),
    "PENATA MUDA TK I": (
        "PENATA MUDA TK I",
        "PENATA MUDA TK.I",
        "PENATA MUDA TINGKAT I",
    ),
    "PENATA": ("PENATA",),
    "PENATA TK I": ("PENATA TK I", "PENATA TK.I", "PENATA TINGKAT I"),
    # Golongan IV (Pembina)
    "PEMBINA": ("PEMBINA",),
    "PEMBINA TK I": ("PEMBINA TK I", "PEMBINA TK.I", "PEMBINA TINGKAT I"),
    "PEMBINA UTAMA MUDA": ("PEMBINA UTAMA MUDA",),
    "PEMBINA UTAMA MADYA": ("PEMBINA UTAMA MADYA",),
    "PEMBINA UTAMA": ("PEMBINA UTAMA",),
}

# Reverse lookup: any variant (uppercased) → canonical form.
_VARIANT_TO_CANONICAL: dict[str, str] = {
    variant.upper(): canonical
    for canonical, variants in PANGKAT_VARIANTS.items()
    for variant in variants
}


def normalize_pangkat(raw: str | None) -> str | None:
    """Return canonical Polri rank, or None if input is empty/unknown."""
    if not raw:
        return None
    cleaned = " ".join(raw.strip().upper().split())
    if cleaned in _VARIANT_TO_CANONICAL:
        return _VARIANT_TO_CANONICAL[cleaned]
    # tolerate trailing punctuation like "AKP."
    stripped = cleaned.rstrip(".,;:")
    return _VARIANT_TO_CANONICAL.get(stripped)


def is_valid_pangkat(raw: str | None) -> bool:
    """True if the string maps to a known Polri rank after normalization."""
    return normalize_pangkat(raw) is not None
