"""Two first-class TIER presets + the synthetic-prompt honesty ride-along (this slice).

  * draft-t2v-1.3b        : t2v 832x480 @16 @ 9 GB -> MUST bind wan2.1-t2v-1.3b.
  * quality-i2v-14b-int8  : i2v 832x480 @16 @ 16 GB -> MUST bind wan2.1-i2v-14b-720p at
                            INT8, and REQUIRES a source (start image) — requires_source.
  * synthetic previews    : ship an EMPTY prompt + a prompt_note badge stating the
                            prompt is recorded but not rendered (no more misleading
                            evocative scaffold).

Router-verified like the existing seeds (studio.router.CapabilityRouter). Script style
matches tests/test_studio_presets_route.py (plain python, numbered PASS/FAIL, nonzero
exit iff any FAILED). pytest is NOT installed in this venv.

Run:
  cd /srv/share/projects/hugpy/dev/abstract_hugpy_dev
  venv/bin/python tests/test_studio_tier_presets.py
"""
from __future__ import annotations

import logging
import os
import sys
import tempfile

logging.disable(logging.INFO)
os.environ.setdefault("STUDIO_ALLOW_UNPINNED", "1")
os.environ.setdefault("PROJECTS_HOME", tempfile.mkdtemp(prefix="studio-tier-test-"))

_SRC = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "src")
if _SRC not in sys.path:
    sys.path.insert(0, _SRC)

import importlib  # noqa: E402

from flask import Flask  # noqa: E402

from abstract_hugpy_dev.video_intel.studio_presets import (  # noqa: E402
    available_studio_presets, get_studio_preset)
from abstract_hugpy_dev.video_intel.studio.job import make_studio_i2v, StudioI2VSpec  # noqa: E402
from abstract_hugpy_dev.video_intel.studio.router import CapabilityRouter  # noqa: E402
from abstract_hugpy_dev.video_intel.studio.schemas import CapabilityRequest, Resolution  # noqa: E402
from abstract_hugpy_dev.video_intel.studio.enums import Capability, Framework, Precision  # noqa: E402

vr = importlib.import_module("abstract_hugpy_dev.flask_app.app.routes.video_routes")
app = Flask(__name__)
app.register_blueprint(vr.video_bp)
client = app.test_client()


def _resolve(preset):
    return CapabilityRouter().resolve(CapabilityRequest(
        capability=Capability(preset.capability),
        target_resolution=Resolution(preset.width, preset.height, preset.fps),
        vram_budget_gb=preset.vram_budget_gb))


# --------------------------------------------------------------------------- #
# [1] Both tier presets are registered and structurally valid (request_body() is a
#     verbatim make_studio_i2v body).
# --------------------------------------------------------------------------- #
def test_tier_presets_registered_and_valid():
    for pid in ("draft-t2v-1.3b", "quality-i2v-14b-int8"):
        p = get_studio_preset(pid)
        assert p is not None, f"{pid} must be registered"
        spec = make_studio_i2v(**p.request_body())
        assert isinstance(spec, StudioI2VSpec), (pid, type(spec))


# --------------------------------------------------------------------------- #
# [2] DRAFT tier @ 9 GB binds the Wan 2.1 T2V 1.3B (and never the synthetic prover).
# --------------------------------------------------------------------------- #
def test_draft_binds_1_3b():
    p = get_studio_preset("draft-t2v-1.3b")
    r = _resolve(p)
    assert r.is_ok(), r
    b = r.unwrap()
    assert b.framework == Framework.WAN and b.model_id == "wan2.1-t2v-1.3b", b
    assert b.framework != Framework.SYNTHETIC, "a real tier must not bind synthetic"


# --------------------------------------------------------------------------- #
# [3] QUALITY tier @ 16 GB binds the Wan 2.1 I2V 14B at INT8, exactly.
# --------------------------------------------------------------------------- #
def test_quality_binds_14b_int8():
    p = get_studio_preset("quality-i2v-14b-int8")
    r = _resolve(p)
    assert r.is_ok(), r
    b = r.unwrap()
    assert b.model_id == "wan2.1-i2v-14b-720p", b.model_id
    assert b.precision == Precision.INT8, b.precision


# --------------------------------------------------------------------------- #
# [4] The QUALITY i2v tier requires a source (start image) — requires_source signal
#     mirrors the restyle preset, and rides the GET list + POST /apply envelope.
# --------------------------------------------------------------------------- #
def test_quality_requires_source_signal():
    p = get_studio_preset("quality-i2v-14b-int8")
    assert p.requires_source is True, "quality i2v needs a start image"
    row = next(x for x in client.get("/video/studio/presets").get_json()["presets"]
               if x["id"] == "quality-i2v-14b-int8")
    assert row.get("requires_source") is True, row
    ap = client.post("/video/studio/presets/quality-i2v-14b-int8/apply").get_json()
    assert ap.get("requires_source") is True, ap
    # requires_source is a UI signal, NOT a make_studio_i2v keyword.
    assert "requires_source" not in ap["request"], ap["request"]


# --------------------------------------------------------------------------- #
# [5] SYNTHETIC previews ship an EMPTY prompt + a prompt_note badge (the evocative
#     "drone shot" scaffold that misled the operator is GONE).
# --------------------------------------------------------------------------- #
def test_synthetic_presets_empty_prompt_with_note():
    for pid in ("quick-preview-synthetic", "preview-t2v-synthetic"):
        p = get_studio_preset(pid)
        assert p.prompt == "", (pid, repr(p.prompt))
        assert p.prompt_note and "not rendered" in p.prompt_note, (pid, p.prompt_note)
        assert "drone" not in (p.prompt or "").lower(), pid


# --------------------------------------------------------------------------- #
# [6] prompt_note rides the GET list (to_dict) but NEVER leaks into request_body.
# --------------------------------------------------------------------------- #
def test_prompt_note_wire_shape():
    row = next(x for x in client.get("/video/studio/presets").get_json()["presets"]
               if x["id"] == "preview-t2v-synthetic")
    assert "prompt_note" in row and "not rendered" in (row["prompt_note"] or ""), row
    assert "prompt_note" not in get_studio_preset("preview-t2v-synthetic").request_body()


# --------------------------------------------------------------------------- #
# [7] Every preset (incl. the two new tiers) still routes to a model — no dead seeds.
# --------------------------------------------------------------------------- #
def test_all_presets_route():
    for p in available_studio_presets():
        r = _resolve(p)
        assert r.is_ok(), (p.id, r.error.code.value if r.is_err() else r)


CHECKS = [
    ("both tier presets registered + request_body() valid", test_tier_presets_registered_and_valid),
    ("draft-t2v-1.3b @9GB binds wan2.1-t2v-1.3b", test_draft_binds_1_3b),
    ("quality-i2v-14b-int8 @16GB binds wan2.1-i2v-14b-720p at INT8", test_quality_binds_14b_int8),
    ("quality i2v requires_source signal (list + apply)", test_quality_requires_source_signal),
    ("synthetic previews: empty prompt + honesty badge, drone scaffold gone",
     test_synthetic_presets_empty_prompt_with_note),
    ("prompt_note rides GET list, never request_body", test_prompt_note_wire_shape),
    ("every preset still routes to a model", test_all_presets_route),
]


def main() -> int:
    passed = failed = 0
    for i, (name, fn) in enumerate(CHECKS, 1):
        try:
            fn()
        except Exception as exc:
            failed += 1
            print(f"[{i}] FAIL  {name}: {type(exc).__name__}: {exc}")
        else:
            passed += 1
            print(f"[{i}] PASS  {name}")
    print(f"\n{passed} passed, {failed} failed of {len(CHECKS)}")
    return 1 if failed else 0


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