import datetime as dt
import json

import pytest

from recoil.execution.providers.atlas import AtlasAdapter
from recoil.execution.providers.base import ProviderJob
from recoil.execution.providers.kling import KlingAdapter
from recoil.execution.providers.piapi import PiApiAdapter
from recoil.execution.providers.wan import WanAdapter


VIDEO_URL = "https://cdn.example.test/video.mp4"


def _job(provider_id: str, *, native_state: dict | None = None) -> ProviderJob:
    return ProviderJob(
        provider_id=provider_id,
        model_id="seeddance-2.0",
        native_id=f"{provider_id}-task",
        tier="standard_720p",
        duration_s=5,
        resolution="720p",
        native_state=native_state or {},
    )


def _adapter(adapter_cls):
    return adapter_cls.__new__(adapter_cls)


def _non_serializable_payload() -> dict:
    return {
        "completed": True,
        "seen_at": dt.datetime(2026, 6, 12, 12, 34, 56),
        "padding": "x" * 700,
    }


CASES = [
    pytest.param(
        KlingAdapter,
        _job("kling"),
        {
            "video": {"url": VIDEO_URL},
            "audio": {"url": "https://cdn.example.test/audio.mp3"},
        },
        {"video": {}, "audio": {}, **_non_serializable_payload()},
        id="kling",
    ),
    pytest.param(
        WanAdapter,
        _job("wan"),
        {"video_url": VIDEO_URL},
        _non_serializable_payload(),
        id="wan",
    ),
    pytest.param(
        PiApiAdapter,
        _job("piapi"),
        {
            "data": {
                "status": "completed",
                "output": {
                    "video": {"url": VIDEO_URL},
                    "audio": {"url": "https://cdn.example.test/audio.mp3"},
                },
                "meta": {"usage": {"consume": 12}},
            }
        },
        {
            "data": {
                "status": "completed",
                "output": {"video": {}},
                **_non_serializable_payload(),
            }
        },
        id="piapi",
    ),
    pytest.param(
        AtlasAdapter,
        _job("atlas"),
        {"data": {"status": "succeeded", "outputs": [VIDEO_URL]}},
        {
            "data": {
                "status": "succeeded",
                "outputs": [],
                **_non_serializable_payload(),
            }
        },
        id="atlas",
    ),
]


@pytest.mark.parametrize("adapter_cls,job,completed_resp,missing_resp", CASES)
def test_parse_result_completed_payload_returns_video_url(
    adapter_cls, job, completed_resp, missing_resp
):
    result = _adapter(adapter_cls).parse_result(completed_resp, job)

    assert result.status == "COMPLETED"
    assert result.video_url == VIDEO_URL
    assert result.error is None


@pytest.mark.parametrize("adapter_cls,job,completed_resp,missing_resp", CASES)
def test_parse_result_completed_without_video_url_fails(
    adapter_cls, job, completed_resp, missing_resp
):
    result = _adapter(adapter_cls).parse_result(missing_resp, job)

    assert result.status == "FAILED"
    assert result.video_url is None
    assert result.raw is missing_resp
    assert result.error is not None
    assert "no video_url" in result.error
    assert json.dumps(missing_resp, default=str, sort_keys=True)[:500] in result.error
