"""render.py — Einheitlicher CLI-Entry-Point für den Bundle-Renderer.

Wrapper auf compose.py (16:9) oder compose_v.py (4:5) je nach --aspect-Wahl.
Konsumenten in Wave H rufen:

    python -m _lib.designsystem.render \
        --aspect 4x5 --template T01v \
        --photo PFAD --headline "..." [...] --output PFAD

Subprocess-Pattern (Playwright-Isolation, kein Import-Konsum).

Logo-Override-Logik (deterministisch, Pflicht-Satz 6):
    1. --logo-path PATH gesetzt              → diese Datei wird eingebettet
    2. --logo gesetzt ohne --logo-path       → Fallback auf
                                               _lib/designsystem/assets/logo-placeholder.svg
    3. Weder --logo noch --logo-path gesetzt → kein Logo
"""

from __future__ import annotations

import argparse
import sys
from pathlib import Path

from _lib.designsystem import compose, compose_v
from _lib.designsystem.resolve import resolve_designsystem


ALLOWED_OUTPUT_SUFFIXES = {".png"}
ALLOWED_PHOTO_MAGIC = {
    b"\x89PNG\r\n\x1a\n": "PNG",
    b"\xff\xd8\xff": "JPEG",
}


def _validate_output_path(path_str: str) -> Path:
    path = Path(path_str)
    if path.suffix.lower() not in ALLOWED_OUTPUT_SUFFIXES:
        raise ValueError(f"--output muss eine PNG-Datei sein, bekommen: {path.suffix}")
    # Path-Traversal-Schutz: keine Aufstiege außerhalb des CWD-Korridors
    resolved = path.resolve()
    cwd_resolved = Path.cwd().resolve()
    try:
        resolved.relative_to(cwd_resolved)
    except ValueError:
        raise ValueError(f"--output liegt außerhalb des erlaubten Korridors (CWD): {resolved}")
    return path


def _validate_photo_path(path_str: str) -> Path:
    path = Path(path_str)
    if not path.exists():
        raise ValueError(f"--photo existiert nicht: {path}")
    with path.open("rb") as f:
        header = f.read(8)
    matched = any(header.startswith(magic) for magic in ALLOWED_PHOTO_MAGIC)
    if not matched:
        raise ValueError(f"--photo ist keine PNG/JPEG-Datei (Magic-Bytes-Check fehlgeschlagen): {path}")
    return path


def _resolve_logo_path(logo_flag: bool, logo_path: Path | None) -> Path | None:
    """Deterministische Logo-Pfad-Auflösung.

    Reihenfolge ohne Try-Except-Fallback (Pflicht-Satz 6): explizite
    Anwender-Wahl, dann Bundle-Default, dann None.
    """
    if logo_path is not None:
        return logo_path
    if logo_flag:
        designsystem_root = resolve_designsystem()
        return designsystem_root / "assets" / "logo-placeholder.svg"
    return None


def main(argv: list[str] | None = None) -> int:
    ap = argparse.ArgumentParser(
        description="Bundle-Renderer für LinkedIn-Thumbnails (Warm Navigator).",
    )
    ap.add_argument("--aspect", required=True, choices=["16x9", "4x5"],
                    help="Aspect-Ratio: 16x9 (1536x1024) oder 4x5 (1080x1350)")
    ap.add_argument("--template", required=True,
                    help="Template-ID (z.B. T01 für 16x9, T01v für 4x5)")
    ap.add_argument("--photo", required=True, type=_validate_photo_path)
    ap.add_argument("--headline", required=True)
    ap.add_argument("--eyebrow", default="")
    ap.add_argument("--logo", action="store_true",
                    help="Logo einbetten. Nutzt --logo-path oder Bundle-Placeholder.")
    ap.add_argument("--logo-path", type=Path, default=None,
                    help="Pfad zur Logo-SVG-Datei (überschreibt Bundle-Placeholder).")
    ap.add_argument("--output", required=True, type=_validate_output_path)
    # Override-Flags (alle optional)
    ap.add_argument("--headline-size", type=float, default=None)
    ap.add_argument("--headline-x", type=float, default=None)
    ap.add_argument("--headline-y", type=float, default=None)
    ap.add_argument("--eyebrow-size", type=float, default=None)
    ap.add_argument("--eyebrow-x", type=float, default=None)
    ap.add_argument("--eyebrow-y", type=float, default=None)
    ap.add_argument("--logo-scale", type=float, default=None)
    ap.add_argument("--logo-x", type=float, default=None)
    ap.add_argument("--logo-y", type=float, default=None)
    ap.add_argument("--block-x", type=float, default=None,
                    help="Block-X-Verschiebung. Nur für Templates mit class=tn-block (T11/T11v).")
    ap.add_argument("--block-y", type=float, default=None,
                    help="Block-Y-Verschiebung. Nur für Templates mit class=tn-block (T11/T11v).")

    args = ap.parse_args(argv)

    # Aspect-spezifisches Modul auswählen
    if args.aspect == "16x9":
        module = compose
    else:
        module = compose_v

    if args.template not in module.TEMPLATES:
        valid = ", ".join(sorted(module.TEMPLATES))
        print(
            f"FEHLER: Template '{args.template}' nicht bekannt für Aspect "
            f"{args.aspect}. Verfügbar: {valid}",
            file=sys.stderr,
        )
        return 2

    if not args.photo.is_file():
        print(f"FEHLER: Foto-Pfad nicht gefunden: {args.photo}", file=sys.stderr)
        return 2

    # Logo-Pfad einmal zentral setzen (gilt für compose und compose_v über
    # gemeinsame Modul-State-Variable in compose._LOGO_PATH).
    logo_path = _resolve_logo_path(args.logo, args.logo_path)
    compose.set_logo_path(logo_path)

    overrides = module.build_override_style(
        args.headline_size, args.headline_x, args.headline_y,
        args.eyebrow_size, args.eyebrow_x, args.eyebrow_y,
        args.logo_scale, args.logo_x, args.logo_y,
        args.block_x, args.block_y,
    )

    module.render(
        args.photo, args.template, args.headline, args.eyebrow,
        args.logo, args.output, overrides,
    )
    print(f"OK: {args.output}")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
