"""Tests for shared/package.py — round-trip and schema validation."""


import pytest
import yaml
from shared.package import (
    PERSONAS_ROOT,
    PackageWriter,
    PersonaManifest,
    load_package,
)

FIXTURE_MANIFEST = {
    "schema_version": 1,
    "slug": "test-persona",
    "display_name": "Test Persona",
    "born": 100,
    "died": 180,
    "voice_policy": "generated",
    "sources": [
        {
            "id": "test-src",
            "type": "book",
            "title": "Test Book",
            "rights": "public-domain",
            "origin_url": "https://example.com/book",
        }
    ],
    "style_summary": "Wise and terse.",
    "fidelity": {"groundedness": 0.0, "style_match": 0.0, "last_eval": None},
}


def test_manifest_round_trip():
    m = PersonaManifest.model_validate(FIXTURE_MANIFEST)
    assert m.slug == "test-persona"
    assert m.display_name == "Test Persona"
    assert len(m.sources) == 1
    assert m.sources[0].id == "test-src"
    assert m.fidelity.groundedness == 0.0
    assert m.retrieval_top_k == 5


def test_default_personas_root_points_at_project_personas():
    assert PERSONAS_ROOT.name == "personas"
    assert PERSONAS_ROOT.parent.name == "MentorCore"


def test_manifest_accepts_retrieval_top_k():
    data = dict(FIXTURE_MANIFEST, retrieval_top_k=8)
    m = PersonaManifest.model_validate(data)
    assert m.retrieval_top_k == 8


def test_manifest_rejects_bad_retrieval_top_k():
    bad = dict(FIXTURE_MANIFEST, retrieval_top_k=0)
    with pytest.raises(Exception):
        PersonaManifest.model_validate(bad)


def test_manifest_rejects_missing_slug():
    bad = dict(FIXTURE_MANIFEST)
    bad["slug"] = ""
    with pytest.raises(Exception):
        PersonaManifest.model_validate(bad)


def test_manifest_rejects_bad_voice_policy():
    bad = dict(FIXTURE_MANIFEST)
    bad["voice_policy"] = "telepathic"
    with pytest.raises(Exception):
        PersonaManifest.model_validate(bad)


def test_manifest_rejects_bad_source_type():
    bad = dict(FIXTURE_MANIFEST)
    bad["sources"] = [dict(FIXTURE_MANIFEST["sources"][0], type="stream")]
    with pytest.raises(Exception):
        PersonaManifest.model_validate(bad)


def test_load_package(tmp_path, monkeypatch):
    monkeypatch.setenv("MENTORCORE_PERSONAS_ROOT", str(tmp_path))

    slug = "test-persona"
    pkg_dir = tmp_path / slug
    pkg_dir.mkdir()
    (pkg_dir / "persona.yaml").write_text(yaml.dump(FIXTURE_MANIFEST))

    m = load_package(slug)
    assert m.slug == slug
    assert m.display_name == "Test Persona"


def test_load_package_not_found(tmp_path, monkeypatch):
    monkeypatch.setenv("MENTORCORE_PERSONAS_ROOT", str(tmp_path))
    with pytest.raises(FileNotFoundError):
        load_package("nonexistent")


def test_package_writer_atomic_swap(tmp_path, monkeypatch):
    monkeypatch.setenv("MENTORCORE_PERSONAS_ROOT", str(tmp_path))

    slug = "test-persona"

    # First build
    with PackageWriter(slug) as w:
        w.write_file("persona.yaml", yaml.dump(FIXTURE_MANIFEST))
        w.write_file("corpus/doc.md", "# Hello")

    pkg_root = tmp_path / slug
    current = pkg_root / "current"
    assert current.is_symlink(), "current should be a symlink after build"
    assert (current / "persona.yaml").exists()
    assert (current / "corpus" / "doc.md").exists()

    # Second build — previous should be retained
    with PackageWriter(slug) as w:
        w.write_file("persona.yaml", yaml.dump(FIXTURE_MANIFEST))

    previous = pkg_root / "previous"
    assert previous.exists(), "previous build should be retained"
    assert current.is_symlink(), "current still exists after second build"


def test_package_writer_load_via_current_symlink(tmp_path, monkeypatch):
    monkeypatch.setenv("MENTORCORE_PERSONAS_ROOT", str(tmp_path))

    slug = "test-persona"
    with PackageWriter(slug) as w:
        w.write_file("persona.yaml", yaml.dump(FIXTURE_MANIFEST))

    m = load_package(slug)
    assert m.slug == slug
