"""p2hs/feature-packs.json loader: `install` entries (existing) are validated here; `compose`
entries (Level 1 capability composition) are returned raw, because they are AI-written intent
that is repaired and validated in one place (_process_pack_compositions) -- an invalid entry
must never be dropped silently, and must never drop a valid entry elsewhere."""
from __future__ import annotations

import json
import tempfile
from pathlib import Path

from src.domain.codegen.feature_packs_manifest import (
    load_compositions_from_repo_path,
    load_manifest_from_repo_path,
)

_QUOTE_COMPOSE_ENTRY = {
    "name": "quote_request",
    "actors": ["anonymous", "admin"],
    "requirements": [
        {"action": "create", "resource": "quote_request", "actor": "anonymous"},
        {"action": "read", "resource": "quote_request", "actor": "admin"},
    ],
    "fields": [{"key": "name", "label": "Name", "type": "text", "required": True}],
}


def _write(root: Path, data: dict) -> None:
    (root / "p2hs").mkdir(parents=True, exist_ok=True)
    (root / "p2hs" / "feature-packs.json").write_text(json.dumps(data), encoding="utf-8")


def test_install_and_compose_parse_independently_in_the_same_file():
    with tempfile.TemporaryDirectory() as raw:
        root = Path(raw)
        _write(root, {
            "version": 1,
            "install": [{"pack_slug": "contact-capture", "config": {}}],
            "compose": [_QUOTE_COMPOSE_ENTRY],
        })
        install = load_manifest_from_repo_path(raw)
        compose = load_compositions_from_repo_path(raw)
    assert install == [{"pack_slug": "contact-capture", "config": {}}]
    assert compose == [_QUOTE_COMPOSE_ENTRY]


def test_an_invalid_compose_entry_is_kept_for_reporting_not_dropped_silently():
    """It used to vanish here, so a required capability could disappear with no record.
    Now it reaches the repair/validate step, which reports it field by field."""
    from src.domain.feature_packs.manifest_repair import repair_composition

    with tempfile.TemporaryDirectory() as raw:
        root = Path(raw)
        bad_entry = {**_QUOTE_COMPOSE_ENTRY, "name": "bad", "requirements": []}  # min_length=1 violated
        _write(root, {"version": 1, "compose": [bad_entry, _QUOTE_COMPOSE_ENTRY, "not-an-object"]})
        compose = load_compositions_from_repo_path(raw)
    assert compose == [bad_entry, _QUOTE_COMPOSE_ENTRY, "not-an-object"]
    statuses = [repair_composition(entry).status for entry in compose]
    assert statuses == ["invalid", "repaired", "invalid"]  # criticality made explicit on the good one


def test_no_compose_array_returns_none():
    with tempfile.TemporaryDirectory() as raw:
        root = Path(raw)
        _write(root, {"version": 1, "install": [{"pack_slug": "contact-capture"}]})
        assert load_compositions_from_repo_path(raw) is None


def test_absent_file_returns_none_for_both():
    with tempfile.TemporaryDirectory() as raw:
        assert load_manifest_from_repo_path(raw) is None
        assert load_compositions_from_repo_path(raw) is None
