"""Boundary test for _resolve_aspect — Law 11.

Phase 2 (bugfix-sprint-post-overhaul): extends the original two cases with
a colon-form rejection / migration test. The contract:

  Disk state with legacy `9:16` aspect → `Project._migrate_legacy` → the
  field_validator `_normalize_aspect` rewrites `9:16` to `9_16` →
  `_resolve_aspect` returns ("9_16", synthesized=True).

The colon form must NEVER survive past the SSOT (the `Project` class).
Anything outside the SSOT that hands a colon-form aspect string into the
HTTP shape is a bug.
"""
from __future__ import annotations

import json

import pytest

from recoil.api.adapters.projects import _resolve_aspect
from recoil.core.project import AspectUnresolvable


def test_resolve_aspect_returns_canonical_underscore_form_for_driver_beware():
    aspect, _synthesized = _resolve_aspect("driver-beware")
    assert aspect in ("9_16", "16_9", "1_1", "4_3")


def test_resolve_aspect_raises_for_missing_project():
    with pytest.raises((AspectUnresolvable, FileNotFoundError, RuntimeError)):
        _resolve_aspect("definitely-not-a-real-project-slug-xyz123")


# ── Phase 2 additions: colon-form migration via SSOT ─────────────────────


@pytest.fixture
def _clean_project_cache():
    """Clear the lru_cache on `core.project.get_project` between tests so
    the temp-dir slug doesn't leak across cases."""
    from recoil.core.project import get_project as _gp
    _gp.cache_clear()
    yield
    _gp.cache_clear()


def _seed_legacy_project(root, slug: str, aspect_value: str) -> None:
    """Build a minimal on-disk project shape:
      projects_root/<slug>/project_config.json   (schema_version=1, aspect_ratio=<aspect_value>)
      projects_root/<slug>/state/visual/global_bible.json   (empty stub)
    """
    proj_dir = root / slug
    (proj_dir / "state" / "visual").mkdir(parents=True, exist_ok=True)
    # global_bible.json is required by the projects adapter for non-legacy
    # status, but its body is not consulted on the aspect path when
    # project_config.json carries an aspect.
    (proj_dir / "state" / "visual" / "global_bible.json").write_text(
        json.dumps({"project": slug}), encoding="utf-8",
    )
    # schema_version<2 + aspect_ratio="9:16" forces the migration ladder
    # in Project._migrate_legacy → field_validator normalizes to "9_16"
    # and stamps aspect_synthesized=True.
    (proj_dir / "project_config.json").write_text(
        json.dumps({
            "schema_version": 1,
            "project_type": "microdrama",
            "aspect_ratio": aspect_value,
            "default_models": {},
        }),
        encoding="utf-8",
    )


def test_resolve_aspect_rejects_colon_form_via_project_class(
    tmp_path, monkeypatch, _clean_project_cache,
):
    """Colon form (`9:16`) on disk migrates to underscore form (`9_16`)
    via Project._migrate_legacy, and _resolve_aspect surfaces synthesized=True.

    This locks the SSOT contract: the only place colon-form is tolerated is
    inside the Project class's _LEGACY_ASPECT_NORMALIZE map, and even then
    it is rewritten before any HTTP-shape adapter ever sees it.
    """
    monkeypatch.setenv("RECOIL_PROJECTS_ROOT", str(tmp_path))
    slug = "phase2-colon-form-project"
    _seed_legacy_project(tmp_path, slug, "9:16")

    aspect, synthesized = _resolve_aspect(slug)

    assert aspect == "9_16", (
        f"_resolve_aspect must rewrite colon form '9:16' to '9_16' "
        f"via Project._migrate_legacy; got {aspect!r}"
    )
    assert synthesized is True, (
        "schema_version<2 with legacy aspect must flag aspect_synthesized=True"
    )


def test_resolve_aspect_passthrough_for_canonical_underscore_form(
    tmp_path, monkeypatch, _clean_project_cache,
):
    """Negative companion: a project that's already on the v2 schema with
    canonical underscore form must NOT be flagged as synthesized."""
    monkeypatch.setenv("RECOIL_PROJECTS_ROOT", str(tmp_path))
    slug = "phase2-canonical-form-project"
    proj_dir = tmp_path / slug
    (proj_dir / "state" / "visual").mkdir(parents=True, exist_ok=True)
    (proj_dir / "state" / "visual" / "global_bible.json").write_text(
        json.dumps({"project": slug}), encoding="utf-8",
    )
    (proj_dir / "project_config.json").write_text(
        json.dumps({
            "schema_version": 2,
            "project_type": "microdrama",
            "aspect_ratio": "16_9",
            "default_models": {},
        }),
        encoding="utf-8",
    )

    aspect, synthesized = _resolve_aspect(slug)

    assert aspect == "16_9"
    assert synthesized is False, (
        "schema_version=2 with canonical aspect must NOT be flagged synthesized"
    )
