"""Capability flag enforcement + structured refusal tests."""

from __future__ import annotations

import sys
from pathlib import Path

import pytest

_RECOIL = Path(__file__).resolve().parents[2]
if str(_RECOIL) not in sys.path:
    sys.path.insert(0, str(_RECOIL))


@pytest.fixture(autouse=True)
def _test_mode(monkeypatch, tmp_path):
    monkeypatch.setenv("RECOIL_PROVIDER_MODE", "test")
    monkeypatch.setenv("FAL_KEY", "x")
    monkeypatch.setenv("ATLAS_CLOUD_API_KEY", "x")
    monkeypatch.setenv("PIAPI_API_KEY", "x")
    monkeypatch.delenv("RECOIL_PROVIDER_OVERRIDE", raising=False)
    from recoil.execution.providers.registry import reset_caches_for_tests
    reset_caches_for_tests()
    yield
    reset_caches_for_tests()


def _ufv(**k):
    from recoil.execution.providers.base import UnifiedVideoPayload
    kwargs = dict(prompt="hi", duration_s=5, resolution="720p", model_id="seeddance-2.0")
    kwargs.update(k)
    return UnifiedVideoPayload(**kwargs)


def test_piapi_refuses_resolution_480p_when_no_exception(monkeypatch):
    """piapi declares resolution_480p=False and no exception in strategy."""
    monkeypatch.setenv("RECOIL_PROVIDER_OVERRIDE", "piapi")
    from recoil.execution.providers.registry import resolve_adapter
    from recoil.execution.providers.base import ProviderCapabilityError
    with pytest.raises(ProviderCapabilityError) as exc:
        resolve_adapter("seeddance-2.0", _ufv(resolution="480p"))
    msg = str(exc.value)
    assert "resolution_480p" in msg
    assert "piapi" in msg
    assert "fal" in msg   # suggestion surfaces


def test_end_frame_exception_avoids_refusal(monkeypatch):
    from recoil.execution.providers.registry import resolve_adapter, reset_caches_for_tests
    monkeypatch.setattr("recoil.execution.providers.registry.load_strategy", lambda force=False: {"seeddance-2.0": {"primary": "piapi", "primary_tier": "seedance-2", "capability_exceptions": {"end_frame": "fal"}}})
    reset_caches_for_tests()
    adapter, tier = resolve_adapter(
        "seeddance-2.0",
        _ufv(image="http://x/a.jpg", image_tail="http://x/b.jpg"),
    )
    assert adapter.provider_id == "fal"  # capability_exceptions wins


def test_explain_capability_returns_structured():
    from recoil.execution.providers.capability import explain_capability
    d = explain_capability("seeddance-2.0", "end_frame")
    assert d["capability"] == "end_frame"
    assert d["route"] == "flora"   # primary wins (seeddance-2.0 primary is flora)
    assert "fal" in d["supported_providers"]


def test_validate_strategy_is_clean():
    """Validate strategy entries have registered adapters.

    CP-8 (Phase 3) added audio_t2a + lipsync_post entries (eleven_multilingual_v2,
    lipsync-2.0) which use a parallel non-ProviderAdapter shape — their
    primaries (elevenlabs, sync_so) are intentionally NOT registered in
    execution/providers/registry.py. Filter them out before validation.

    CP-9 (Phase 3) adds the text_multimodal eval modality
    (gemini-3.1-pro-preview → gemini_vision) which is reached via the
    Phase 2 score_artifact() function rather than the ProviderAdapter
    Protocol; it is excluded for the same reason.
    """
    import json
    from pathlib import Path as _Path
    from recoil.execution.providers.capability import validate_strategy
    from recoil.execution.providers.registry import load_strategy
    profiles_path = _Path(__file__).resolve().parents[2] / "config" / "model_profiles.json"
    profiles = json.loads(profiles_path.read_text())
    NON_PROTOCOL_MODALITIES = {"audio_t2a", "lipsync_post", "text_multimodal"}
    strategy = {
        k: v for k, v in load_strategy().items()
        if k.startswith("__")
        or k == "schema_version"
        or (
            isinstance(profiles.get(k), dict)
            and profiles.get(k, {}).get("modality") not in NON_PROTOCOL_MODALITIES
        )
    }
    problems = validate_strategy(strategy)
    assert problems == []
