# SDR: sdr-0024 — gera as três tabelas curadas em Informacoes-gerais/ a partir do legado.
# Uso: python scripts/gerar_referencia_cmdb_informacoes_gerais.py

from __future__ import annotations

import re
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]
LEGADO = ROOT / "Informacoes-gerais" / "cmdb_datacenter_itens_configuracao-LEGADO-IA.md"
OUT_FAC = ROOT / "Informacoes-gerais" / "referencia-cmdb-facility.md"
OUT_TI = ROOT / "Informacoes-gerais" / "referencia-cmdb-ti-infra.md"
OUT_SW = ROOT / "Informacoes-gerais" / "referencia-cmdb-software-entrega.md"

META_TOTAL = 800
SKIP_SECTIONS = {14, 19, 26, 27, 28}


def tipo_heuristic(nome: str) -> str:
    n = nome.lower()
    if any(x in n for x in ("papel", "dono", "responsável", "mapa de", "cadeia de", "topologia de", "ponto de")):
        return "Documento"
    if any(x in n for x in ("serviço", "service ", "pipeline", "job de", "repositório de", "branch de")):
        return "Serviço"
    if any(
        x in n
        for x in (
            "firmware",
            "módulo",
            "disco ",
            "memória",
            "ventoin",
            "fonte de alimentação",
            "placa ",
            "bateria",
            "dimm",
            "transceiver",
            "cordão",
            "cabo ",
        )
    ):
        return "Componente"
    return "CI"


def remun_tipico(tipo: str, nome: str) -> str:
    if tipo in ("Documento", "Papel"):
        return "Não"
    if tipo == "Serviço":
        return "Opcional"
    if tipo == "Componente":
        return "Não"
    return "Se catálogo"


def acoes_c1_c2_c3(tipo: str, sec: int) -> tuple[str, str, str]:
    if tipo == "Documento":
        return ("Custódia/evidência", "Consumo", "Consumo")
    if tipo == "Papel":
        return ("Cadastro/RACI", "Operação", "Postura")
    if tipo == "Serviço":
        return ("IMR/SLA", "Execução", "Controles C3 quando aplicável")
    if sec <= 4:
        return ("Medição predial", "Operação/manutenção", "Físico/lógico C3 se sensível")
    if sec in (5, 6, 8, 10, 11, 22, 23):
        return ("Congelamento/IMR", "Operação/mudança", "Proteção/patch")
    if sec == 9:
        return ("Inventário/orquestração", "SRE/plataforma", "Políticas/sec")
    if sec in (12, 13, 18, 20, 21):
        return ("Ateste/dados", "Suporte app", "Dados/seg app")
    return ("Medição", "Operação", "Segurança")


def parse_legado(text: str) -> list[dict]:
    sec_idx = 0
    sec_title = ""
    items: list[dict] = []
    sec_heading = re.compile(r"^## (\d+)\.\s+(.+)$")
    item_line = re.compile(r"^(\d+)\.\s+(.+)$")
    for line in text.splitlines():
        m = sec_heading.match(line)
        if m:
            sec_idx = int(m.group(1))
            sec_title = m.group(2).strip()
            continue
        m = item_line.match(line)
        if m and sec_idx and sec_idx not in SKIP_SECTIONS:
            items.append(
                {
                    "legado_num": int(m.group(1)),
                    "nome": m.group(2).strip(),
                    "sec": sec_idx,
                    "sec_title": sec_title,
                }
            )
    return items


def fac_sec(sec: int) -> bool:
    return sec in (1, 2, 3, 4)


def ti_sec(sec: int) -> bool:
    return sec in (5, 6, 7, 8, 10, 11, 15, 16, 22, 23, 24, 25)


def sw_sec(sec: int) -> bool:
    return sec in (9, 12, 13, 17, 18, 20, 21)


def key(x: dict) -> tuple[int, str]:
    return (x["legado_num"], x["nome"])


def emit(path: Path, title: str, rows: list[dict], prefix: str) -> None:
    lines = [
        f"# {title}",
        "",
        "Norma: [sdr-0024-cmdb-taxonomia-referencia-projeto.md](../SDRs/sdr-0024-cmdb-taxonomia-referencia-projeto.md) · Legado: [cmdb_datacenter_itens_configuracao-LEGADO-IA.md](./cmdb_datacenter_itens_configuracao-LEGADO-IA.md)",
        "",
        "| ID | Nome | TipoMeta | Atributos_chave | Gestão_CMDB | Remun_tipico | C1-GOV | C2-OPR | C3-SEC | Justificativa |",
        "|----|------|----------|-----------------|-------------|--------------|--------|--------|--------|-----------------|",
    ]
    for i, r in enumerate(rows, start=1):
        tid = f"{prefix}-{i:03d}"
        tipo = tipo_heuristic(r["nome"])
        if tipo == "CI" and "diretório" in r["nome"].lower():
            tipo = "Serviço"
        attrs = f"sec_legado={r['sec']}; orig={r['legado_num']}"
        gest = "Sim"
        rem = remun_tipico(tipo, r["nome"])
        c1, c2, c3 = acoes_c1_c2_c3(tipo, r["sec"])
        nome_esc = r["nome"].replace("|", "/")
        just = (
            f"Curado do legado §{r['sec']} ({r['sec_title']}); "
            "ambiente/criticidade como atributos CMDB, não como linhas duplicadas."
        )
        lines.append(
            f"| {tid} | {nome_esc} | {tipo} | {attrs} | {gest} | {rem} | {c1} | {c2} | {c3} | {just} |"
        )
    lines.append("")
    lines.append(f"**Total de linhas:** {len(rows)}")
    path.write_text("\n".join(lines), encoding="utf-8")


def main() -> None:
    if not LEGADO.is_file():
        raise SystemExit(f"Legado não encontrado: {LEGADO}")
    raw = parse_legado(LEGADO.read_text(encoding="utf-8"))
    fac_pool = [x for x in raw if fac_sec(x["sec"])]
    ti_pool = [x for x in raw if ti_sec(x["sec"])]
    sw_pool = [x for x in raw if sw_sec(x["sec"])]

    fac = fac_pool[: min(250, len(fac_pool))]
    used = {key(x) for x in fac}

    sw: list[dict] = []
    for x in sw_pool:
        if len(sw) >= 150:
            break
        if key(x) in used:
            continue
        sw.append(x)
        used.add(key(x))

    ti: list[dict] = []
    need_ti = META_TOTAL - len(fac) - len(sw)
    for x in ti_pool:
        if len(ti) >= need_ti:
            break
        if key(x) in used:
            continue
        ti.append(x)
        used.add(key(x))

    while len(fac) + len(sw) + len(ti) < META_TOTAL:
        progressed = False
        for x in raw:
            if len(fac) + len(sw) + len(ti) >= META_TOTAL:
                break
            if key(x) in used:
                continue
            ti.append(x)
            used.add(key(x))
            progressed = True
        if not progressed:
            break

    bundle = (fac + sw + ti)[:META_TOTAL]
    fac_f = [x for x in bundle if fac_sec(x["sec"])][:250]
    sw_f = [x for x in bundle if sw_sec(x["sec"])][:150]
    used_b = {key(x) for x in fac_f + sw_f}
    ti_f = [x for x in bundle if key(x) not in used_b][: META_TOTAL - len(fac_f) - len(sw_f)]
    while len(fac_f) + len(sw_f) + len(ti_f) < META_TOTAL:
        for x in raw:
            if len(fac_f) + len(sw_f) + len(ti_f) >= META_TOTAL:
                break
            if key(x) in {key(y) for y in fac_f + sw_f + ti_f}:
                continue
            ti_f.append(x)

    fac_f = fac_f[:250]
    sw_f = sw_f[:150]
    ti_f = ti_f[: META_TOTAL - len(fac_f) - len(sw_f)]

    if len(fac_f) + len(sw_f) + len(ti_f) != META_TOTAL:
        raise SystemExit(
            f"Contagem final inválida: FAC={len(fac_f)} SW={len(sw_f)} TI={len(ti_f)} "
            f"sum={len(fac_f) + len(sw_f) + len(ti_f)}"
        )

    emit(OUT_FAC, "Referência CMDB — Facility e predial", fac_f, "FAC")
    emit(OUT_TI, "Referência CMDB — TI e infraestrutura", ti_f, "TI")
    emit(OUT_SW, "Referência CMDB — Software, plataforma e entrega", sw_f, "SW")
    print(f"OK: FAC={len(fac_f)} TI={len(ti_f)} SW={len(sw_f)} TOTAL={META_TOTAL}")


if __name__ == "__main__":
    main()
