"""Download-Workflow: lädt das PDF eines Belegs nach Temp und gibt OCR-Metadaten aus.

Sicherheits-Vertrag:

- Das PDF wandert direkt aus der HTTP-Response auf Disk, nicht durch
  Python-Returns.
- ``fileContent`` wird vom Bridge-Helfer rekursiv aus jedem Response
  entfernt. Der JSON-Output enthält ``fileContent`` garantiert NICHT,
  auch nicht unter geschachtelten Schlüsseln wie ``ocr_metadata.*``
  oder ``document.*``.

Default-Target ist ``tempfile.gettempdir() / 'gmi-accountant'``.
"""
from __future__ import annotations

import argparse
import json
import sys
import tempfile
from pathlib import Path
from typing import Optional


_SKILL_DIR = Path(__file__).resolve().parent.parent
_SKILLS_ROOT = _SKILL_DIR.parent
if str(_SKILLS_ROOT) not in sys.path:
    sys.path.insert(0, str(_SKILLS_ROOT))
if str(_SKILL_DIR) not in sys.path:
    sys.path.insert(0, str(_SKILL_DIR))


def _default_target() -> Path:
    return Path(tempfile.gettempdir()) / "gmi-accountant"


def _allowed_target_roots() -> list[Path]:
    """Erlaubte Wurzeln für ``--target`` (Wave-1-Lesson 10 / Post-Tag H-H2).

    System-Temp ist die Default-Wurzel. Wer in einem anderen Pfad schreiben
    will, setzt die Env-Var ``GMI_ACCOUNTANT_ALLOWED_TARGET_ROOTS`` als
    Komma-getrennte Liste (z.B. Vault-Datei-Pfad, alternatives Tempverzeichnis).
    Pfad-Containment-Check verhindert ``../``-Traversal zu sensiblen
    Systembereichen.
    """
    import os  # lokal, weil oben nicht mehr global gebraucht
    roots = [Path(tempfile.gettempdir()).resolve()]
    extra = os.environ.get("GMI_ACCOUNTANT_ALLOWED_TARGET_ROOTS", "")
    for raw in extra.split(","):
        raw = raw.strip()
        if raw:
            roots.append(Path(raw).resolve())
    return roots


def _resolve_safe_target(target: Optional[str]) -> Optional[Path]:
    """Resolved den Target-Pfad und prüft Containment gegen erlaubte Wurzeln.

    Returns None bei Containment-Verletzung (Aufrufer printet error + exit 2).
    """
    if not target:
        return _default_target()
    resolved = Path(target).resolve()
    allowed = _allowed_target_roots()
    if any(resolved == root or root in resolved.parents for root in allowed):
        return resolved
    return None


def run(uid: int, target: Optional[str]) -> int:
    try:
        from gmi_bridge import (  # noqa: WPS433
            build_client,
            download_pdf,
            fetch_one_document_meta_via_list,
        )
    except (FileNotFoundError, ImportError) as e:
        print(json.dumps({"error": f"depends_on-Vertrag verletzt: {e}"}, ensure_ascii=False))
        return 3

    try:
        client = build_client()
    except Exception:
        print(json.dumps({"error": "Bridge konnte nicht aufgebaut werden."}, ensure_ascii=False))
        return 2

    target_dir = _resolve_safe_target(target)
    if target_dir is None:
        print(json.dumps({
            "error": (
                "Pfad aus --target liegt außerhalb der erlaubten Wurzeln "
                "(System-Temp oder GMI_ACCOUNTANT_ALLOWED_TARGET_ROOTS). "
                "Path-Traversal-Schutz aktiv."
            ),
        }, ensure_ascii=False))
        return 2
    target_dir.mkdir(parents=True, exist_ok=True)
    pdf_path = target_dir / f"{uid}.pdf"

    try:
        download_pdf(client, uid, str(pdf_path))
        meta_raw = fetch_one_document_meta_via_list(client, uid)
    except Exception as e:
        print(json.dumps({
            "error": f"Download oder Metadaten-Fetch fehlgeschlagen: {type(e).__name__}",
        }, ensure_ascii=False))
        return 1

    meta = meta_raw.get("meta_data", meta_raw) if isinstance(meta_raw, dict) else {}
    ocr_meta = {
        "supplier": meta.get("companyName", ""),
        "documentNumber": meta.get("documentNumber"),
        "documentDate": meta.get("documentDate"),
        "grossAmount": meta.get("grossAmount"),
        "currency": meta.get("currency"),
        "documentType": meta.get("documentType"),
    }
    result = {
        "uid": uid,
        "pdf_path": str(pdf_path),
        "ocr_metadata": ocr_meta,
    }
    # Defense in depth: vor dem Druck noch einmal fileContent rekursiv
    # entfernen (sollte vom Bridge-Helfer schon erledigt sein).
    result = _strip_filecontent_recursive(result)
    print(json.dumps(result, ensure_ascii=False, indent=2))
    return 0


def _strip_filecontent_recursive(obj):
    """Letzter Sicherheitsnetz: fileContent auf allen Tiefen entfernen."""
    if isinstance(obj, dict):
        return {
            k: _strip_filecontent_recursive(v)
            for k, v in obj.items()
            if k != "fileContent"
        }
    if isinstance(obj, list):
        return [_strip_filecontent_recursive(x) for x in obj]
    return obj


def main() -> int:
    p = argparse.ArgumentParser(description="gmi-accountant Download")
    p.add_argument("--uid", type=int, required=True)
    p.add_argument("--target", default=None,
                   help=f"Zielordner (Default: {_default_target()}).")
    args = p.parse_args()
    return run(args.uid, args.target)


if __name__ == "__main__":
    sys.exit(main())
