"""Flora adapter — all Kling flavors (t2v / i2v / f2v / r2v) endpoint mapping.

Offline, no network: https ref/image URLs skip the upload path in
build_submit, so no Flora I/O is triggered. Asserts each (model_id, action)
resolves to the EXACT live endpoint id from
consultations/recoil/flora-kling-adapter-2026-06-23/LIVE_KLING_ENDPOINTS.md.
"""

from __future__ import annotations

import importlib

import pytest

from recoil.execution.providers import flora as flora_mod
from recoil.execution.providers.base import UnifiedVideoPayload
from recoil.execution.providers.flora import FloraAdapter

REF_URL = "https://example.test/ref.png"
START_URL = "https://example.test/start.png"
END_URL = "https://example.test/end.png"


@pytest.fixture(autouse=True)
def _flora_env(monkeypatch):
    monkeypatch.setenv("FLORA_API_KEY", "test-key")
    monkeypatch.setenv("RECOIL_FLORA_WORKSPACE", "ws_test")
    monkeypatch.setenv("RECOIL_FLORA_PROJECT", "prj_test")


def _payload(model_id: str, action: str) -> UnifiedVideoPayload:
    if action == "t2v":
        return UnifiedVideoPayload(prompt="render", model_id=model_id)
    if action == "i2v":
        return UnifiedVideoPayload(prompt="render", model_id=model_id, image=START_URL)
    if action == "f2v":
        return UnifiedVideoPayload(
            prompt="render", model_id=model_id, image=START_URL, image_tail=END_URL
        )
    if action == "r2v":
        return UnifiedVideoPayload(
            prompt="render", model_id=model_id, reference_images=[REF_URL]
        )
    raise AssertionError(f"unknown action {action}")


def _image_field(body: dict, key: str):
    """Return the value of an image-input key wherever placement put it."""
    if key in body:
        return body[key]
    return body.get("params", {}).get(key)


# (model_id, action) -> exact live Flora endpoint id
MATRIX = {
    ("kling-o3-pro", "t2v"): "t2v-kling-o3",
    ("kling-o3-pro", "i2v"): "i2v-kling-o3",
    ("kling-o3-pro", "f2v"): "f2v-kling-o3",
    ("kling-o3-pro", "r2v"): "r2v-kling-o3",
    ("kling-3.0-pro", "t2v"): "t2v-kling-v3-pro",
    ("kling-3.0-pro", "i2v"): "i2v-kling-3-0-pro-turbo-i2v",
    ("kling-3.0-pro", "f2v"): "f2v-kling-v3-pro",
    ("kling-2.5-pro", "t2v"): "t2v-kling-2.5",
    ("kling-2.5-pro", "i2v"): "i2v-kling-2.5",
    ("kling-2.5-pro", "f2v"): "f2v-kling-2.5-pro",
}


@pytest.mark.parametrize(("key", "expected"), list(MATRIX.items()))
def test_kling_flavor_resolves_to_live_endpoint(key, expected):
    model_id, action = key
    body = FloraAdapter().build_submit(_payload(model_id, action), "standard").body
    assert body["model"] == expected
    assert body["type"] == "video"


def test_f2v_carries_both_start_and_end_frame():
    body = FloraAdapter().build_submit(
        _payload("kling-o3-pro", "f2v"), "standard"
    ).body
    assert _image_field(body, "image_url") == START_URL
    assert _image_field(body, "end_image_url") == END_URL


def test_r2v_refs_land_in_image_urls():
    body = FloraAdapter().build_submit(
        _payload("kling-o3-pro", "r2v"), "standard"
    ).body
    assert _image_field(body, "image_urls") == [REF_URL]


def test_dead_v3_pro_i2v_endpoint_is_not_emitted():
    """Non-vacuous: under the OLD table this resolved to the DEAD
    `i2v-kling-v3-pro` (a 404 endpoint). The fix routes it to the live
    Pro-Turbo id. Both halves are asserted so the old table fails this test.
    """
    body = FloraAdapter().build_submit(
        _payload("kling-3.0-pro", "i2v"), "standard"
    ).body
    assert body["model"] == "i2v-kling-3-0-pro-turbo-i2v"
    assert body["model"] != "i2v-kling-v3-pro"


def test_image_field_placement_flag_moves_image_url(monkeypatch):
    """Flipping the single-point-of-truth constant moves image_url between
    params and the body top level; tuning keys stay in params either way.
    """
    payload = _payload("kling-o3-pro", "i2v")

    # Default (False): image_url lives in params, not top level.
    monkeypatch.setattr(
        flora_mod, "_FLORA_VIDEO_IMAGE_FIELDS_AT_TOPLEVEL", False, raising=True
    )
    body = FloraAdapter().build_submit(payload, "standard").body
    assert body["params"].get("image_url") == START_URL
    assert "image_url" not in body
    assert "resolution" in body["params"]  # tuning key stays in params

    # Flipped (True): image_url moves to top level, leaves params.
    monkeypatch.setattr(
        flora_mod, "_FLORA_VIDEO_IMAGE_FIELDS_AT_TOPLEVEL", True, raising=True
    )
    body = FloraAdapter().build_submit(payload, "standard").body
    assert body.get("image_url") == START_URL
    assert "image_url" not in body["params"]
    assert "resolution" in body["params"]  # tuning key still in params


def _png_bytes() -> bytes:
    return b"\x89PNG\r\n\x1a\n" + b"\x00" * 64


def test_local_f2v_frames_are_uploaded(monkeypatch, tmp_path):
    """LOCAL f2v start+end frame PATHS must be hosted before submit."""
    uploaded: list = []

    def _fake_upload(paths, *a, **k):
        uploaded.extend(paths)
        return [f"https://flora.test/hosted/{i}.png" for i, _ in enumerate(paths)]

    monkeypatch.setattr(flora_mod, "_upload_local_refs", _fake_upload)
    start = tmp_path / "start.png"; start.write_bytes(_png_bytes())
    end = tmp_path / "end.png"; end.write_bytes(_png_bytes())
    payload = UnifiedVideoPayload(
        prompt="render", model_id="kling-o3-pro",
        image=str(start), image_tail=str(end),
    )
    req = FloraAdapter().build_submit(payload, "standard")

    assert str(start) in uploaded and str(end) in uploaded
    end_val = req.body["params"].get("end_image_url") or req.body.get("end_image_url")
    start_val = req.body["params"].get("image_url") or req.body.get("image_url")
    assert end_val and end_val.startswith("https://")
    assert start_val and start_val.startswith("https://")


def test_base64_frames_are_decoded_and_uploaded(monkeypatch):
    """BASE64 frame bytes (the inline shape dispatch_payload produces for i2v/f2v)
    must be decoded to a temp file and uploaded — NOT passed as a path or dropped.
    This is the integration bug the live probe surfaced."""
    import base64 as _b64

    uploaded: list = []

    def _fake_upload(paths, *a, **k):
        uploaded.extend(paths)
        return [f"https://flora.test/hosted/{i}.png" for i, _ in enumerate(paths)]

    monkeypatch.setattr(flora_mod, "_upload_local_refs", _fake_upload)
    b64 = _b64.b64encode(_png_bytes()).decode()
    payload = UnifiedVideoPayload(
        prompt="render", model_id="kling-o3-pro",
        image=b64, image_tail=b64,
    )
    req = FloraAdapter().build_submit(payload, "standard")

    # Both base64 inputs were decoded to temp files and routed through upload...
    assert len(uploaded) == 2
    assert all(p.endswith(".png") and "/" in p for p in uploaded)
    # ...and the body carries hosted https URLs, not raw base64.
    end_val = req.body["params"].get("end_image_url") or req.body.get("end_image_url")
    start_val = req.body["params"].get("image_url") or req.body.get("image_url")
    assert start_val.startswith("https://") and end_val.startswith("https://")


def test_image_field_placement_flag_default_is_false():
    """Guard the shipped default: image fields stay in params until the
    paid probe confirms otherwise (parent flips ONE line)."""
    importlib.reload(flora_mod)
    assert flora_mod._FLORA_VIDEO_IMAGE_FIELDS_AT_TOPLEVEL is False
