"""Command-line interface for opentranscode.

Provides three flags:
  - ``--version``      — print the package version and exit (0).
  - ``--dry-run``      — probe the environment, run the av1an VSScript
    smoke test if av1an is available, print a report, and exit. Does
    NOT launch the GUI and does NOT encode anything.
  - ``--verify-only PATH`` — re-verify an existing output file's size,
    resolution, and duration via ffprobe, without re-encoding.

With no flag, ``main()`` defers to ``ui_window.launch_gui()``.

Heavy imports (``env_probe``, ``ffprobe_utils``, ``ui_window``) are
deferred into the bodies of ``run_dry_run`` / ``run_verify_only`` /
the no-flag branch so that ``--version`` does not pull in PySide6.

Extracted from ``open-transcode.v3.py`` (QA item v4-03 — package split).
This is a pure code-organization refactor; behavior is identical to v3.
"""

from __future__ import annotations

import argparse
import sys
from pathlib import Path


def build_parser() -> argparse.ArgumentParser:
    """Build the CLI argument parser."""
    parser = argparse.ArgumentParser(
        prog="opentranscode",
        description="Open-source batch video transcoder (av1an + ffmpeg)",
    )
    parser.add_argument(
        "--version", action="store_true",
        help="Print version and exit",
    )
    parser.add_argument(
        "--dry-run", action="store_true",
        help="Probe environment, run smoke test, print report — but do "
             "NOT launch GUI or encode anything",
    )
    parser.add_argument(
        "--verify-only", metavar="PATH",
        help="Re-verify an existing output file (size, resolution, "
             "duration checks) without re-encoding",
    )
    # v5-01: --force pre-checks the "Force (skip validation)" checkbox in
    # the GUI. This is a convenience flag — the checkbox can also be toggled
    # manually in the UI.
    parser.add_argument(
        "--force", action="store_true",
        help="Pre-check the 'Force (skip validation)' checkbox in the GUI. "
             "Skips ffprobe pre-validation and attempts encode even for "
             "files ffprobe cannot read. WARNING: invalid files will waste "
             "the full per-file timeout before failing.",
    )
    return parser


def run_dry_run() -> int:
    """Run the dry-run: probe env + smoke test, print report, return exit code."""
    # Deferred imports so --version never pulls in PySide6 or runs the
    # environment probe.
    from . import __version__
    from .env_probe import _av1an_vsscript_smoke_test, probe_environment

    print(f"opentranscode {__version__} — dry-run environment probe")
    print("=" * 60)

    env = probe_environment()

    print(f"Distro:        {env.distro.name} (family={env.distro.family}, "
          f"v{env.distro.version_id})")
    print(f"CPU:           {env.cpu.model_name} — "
          f"{env.cpu.physical_cores} physical / {env.cpu.logical_threads} logical")
    print(f"av1an:         {env.av1an_path or 'NOT FOUND'}"
          + (f" (v{env.av1an_version})" if env.av1an_version else ""))
    print(f"ffmpeg:        {env.ffmpeg_path or 'NOT FOUND'}"
          + (f" (v{env.ffmpeg_version})" if env.ffmpeg_version else ""))
    print(f"ffprobe:       {env.ffprobe_path or 'NOT FOUND'}")
    print(f"VapourSynth:   {env.vs_version or 'NOT FOUND'}"
          + (f" ({env.vs_script_lib})" if env.vs_script_lib else ""))
    print("ffmpeg libs:   " + ", ".join(
        f"{k}={'yes' if v else 'no'}" for k, v in sorted(env.ffmpeg_libs.items())
    ))
    if env.errors:
        print("\nERRORS:")
        for e in env.errors:
            print(f"  - {e}")
    if env.warnings:
        print("\nWARNINGS:")
        for w in env.warnings:
            print(f"  - {w}")

    # Smoke test only if av1an + ffmpeg are both present.
    if env.av1an_path and env.ffmpeg_path:
        print("\n--- av1an VSScript smoke test ---")
        svt_name = (env.av1an_flags or {}).get("svt_name", "svt_av1")
        ok, detail = _av1an_vsscript_smoke_test(
            env.av1an_path, env.ffmpeg_path, env.av1an_flags, svt_name,
        )
        print(f"  result: {'OK' if ok else 'FAIL'}")
        print(f"  detail: {detail}")
        if not ok:
            print("\nDry-run complete — smoke test FAILED.")
            return 1
    else:
        print("\nSmoke test skipped (av1an or ffmpeg not found).")

    print("\nDry-run complete.")
    return 0 if not env.errors else 1


def run_verify_only(path: str) -> int:
    """Re-verify an existing output file via ffprobe (no re-encode)."""
    import os

    from .ffprobe_utils import ffprobe_duration, ffprobe_validate

    target = Path(path)
    if not target.is_file():
        print(f"verify-only: file not found: {target}", file=sys.stderr)
        return 1

    ffprobe_bin = os.environ.get("FFPROBE_BIN", "ffprobe")
    info = ffprobe_validate(target, ffprobe_bin)
    if info is None:
        print(f"verify-only: ffprobe could not read {target}", file=sys.stderr)
        return 1

    size = target.stat().st_size
    duration = ffprobe_duration(target, ffprobe_bin)
    streams = info.get("streams", [])
    vstream = next((s for s in streams if s.get("codec_type") == "video"), {})
    width = vstream.get("width", "?")
    height = vstream.get("height", "?")

    print(f"file:      {target}")
    print(f"size:      {size} bytes ({size / 1024 / 1024:.2f} MiB)")
    print(f"duration:  {duration if duration is not None else '?'} s"
          if duration is not None else "duration:  ?")
    print(f"resolution: {width}x{height}")
    print("\nverify-only: OK" if size > 0 else "\nverify-only: FAIL (empty file)")
    return 0 if size > 0 else 1


def main(argv: list[str] | None = None) -> int:
    """CLI entry point. Returns the process exit code."""
    args = build_parser().parse_args(argv)
    if args.version:
        from . import __version__
        print(f"opentranscode {__version__}")
        return 0
    if args.dry_run:
        return run_dry_run()
    if args.verify_only:
        return run_verify_only(args.verify_only)
    # No flag (or --force) — launch GUI. --force pre-checks the Force
    # checkbox; the user can still toggle it in the UI.
    from .ui_window import launch_gui
    return launch_gui(force=args.force)
