from __future__ import annotations

from collections.abc import Mapping
from datetime import datetime
from typing import Any


_AUDIT_STATUS_LABELS = {
    "aprobado": "aprobado",
    "corregido": "corregido",
    "validado_automaticamente": "validado_automaticamente",
}


def _text(value: Any) -> str:
    return str(value or "").strip()


def _date_value(value: Any) -> str:
    if isinstance(value, datetime):
        return value.isoformat()
    return _text(value)


def _preparation_override_list(values: Any) -> list[Any]:
    if isinstance(values, Mapping):
        return list(values.get("pdf_preparation_overrides") or [])
    return list(values) if isinstance(values, list) else []


def _decision_projection(raw: Mapping[str, Any]) -> dict[str, str]:
    return {
        "decision": _text(raw.get("decision")),
        "actor": _text(raw.get("actor")),
        "fecha": _date_value(raw.get("decided_at") or raw.get("fecha")),
        "motivo": _text(raw.get("reason") or raw.get("motivo")),
        "codigo_original": _text(raw.get("original_code") or raw.get("codigo_original")),
        "descripcion_original": _text(
            raw.get("original_description") or raw.get("descripcion_original")
        ),
        "codigo_corregido": _text(raw.get("corrected_code") or raw.get("codigo_corregido")),
        "descripcion_corregida": _text(
            raw.get("corrected_description") or raw.get("descripcion_corregida")
        ),
    }


def _preparation_change_projection(raw: Mapping[str, Any]) -> dict[str, str]:
    return {
        "campo": _text(raw.get("field") or raw.get("campo")),
        "valor_anterior": _text(raw.get("original_value") or raw.get("valor_anterior")),
        "valor_nuevo": _text(raw.get("new_value") or raw.get("valor_nuevo")),
        "actor": _text(raw.get("actor")),
        "fecha": _date_value(raw.get("changed_at") or raw.get("fecha")),
        "motivo": _text(raw.get("reason") or raw.get("motivo")),
    }


def project_auditoria_traceability(
    item: Mapping[str, Any] | None,
    *,
    section: str,
    preparation_overrides: Any = None,
) -> dict[str, Any]:
    """Project human decisions and later PDF edits without inventing history."""
    source = item if isinstance(item, Mapping) else {}
    decisions = [
        _decision_projection(raw)
        for raw in source.get("decisions") or []
        if isinstance(raw, Mapping)
    ]
    status = _text(source.get("status") or source.get("estado_codificacion"))
    existing_trace = source.get("auditoria")
    if not decisions and not status and isinstance(existing_trace, Mapping):
        decisions = [
            _decision_projection(raw)
            for raw in existing_trace.get("decisiones") or []
            if isinstance(raw, Mapping)
        ]
        status = _text(existing_trace.get("estado_final"))
    if decisions:
        final_status = {
            "approve": "aprobado",
            "correct": "corregido",
            "reject": "rechazado",
            "reopen": "pendiente_revision",
        }.get(decisions[-1]["decision"], status or "sin_registro_humano")
        if status in _AUDIT_STATUS_LABELS:
            final_status = status
    elif status == "validado_automaticamente":
        final_status = "validado_automaticamente"
    else:
        final_status = "sin_registro_humano"

    item_key = _text(source.get("item_id") or source.get("key"))
    changes: list[dict[str, str]] = []
    for override in _preparation_override_list(preparation_overrides):
        if not isinstance(override, Mapping):
            continue
        if _text(override.get("section")) != section or _text(override.get("item_key")) != item_key:
            continue
        changes.extend(
            _preparation_change_projection(entry)
            for entry in override.get("history") or []
            if isinstance(entry, Mapping) and _text(entry.get("field") or entry.get("campo"))
        )
        break

    automatic = source.get("automatic")
    if not isinstance(automatic, Mapping):
        automatic = {
            "applied": False,
            "strategy": _text(source.get("canonical_strategy")),
            "strategy_version": _text(source.get("canonical_strategy_version")),
            "timestamp": "",
            "reason": "",
            "suggested_value": "",
            "related_occurrences": [],
        }
    incidents = [
        dict(item)
        for item in (source.get("canonical_incidents") or source.get("incidencias") or [])
        if isinstance(item, Mapping)
    ]
    evidences = [
        dict(item)
        for item in source.get("evidencias") or source.get("evidence") or []
        if isinstance(item, Mapping)
    ]
    return {
        "estado_final": final_status,
        "revision_humana": bool(decisions),
        "decisiones": decisions,
        "cambios_preparacion": changes,
        "automatic": dict(automatic),
        "evidencias": evidences,
        "incidencias": incidents,
    }
