"""Tests for stage 080 generated artifacts."""

import json
from pathlib import Path

import pytest

from accountable_record.errors import StageInputMalformed, StageInputMissing
from accountable_record.stage_080_generated.base import constants
from accountable_record.stage_080_generated.collect import collect_generated_elements
from accountable_record.stage_080_generated.model import (
    GeneratedArtifact,
    GeneratedElementRecord,
    GeneratedReconciliation,
    GeneratedRegistry,
)


def write_generated_element(
    *,
    repo_root: Path,
    category: str = "example",
    local_name: str,
    compact_id: str,
) -> Path:
    """Write one generated/exported element JSON artifact."""
    element_dir = (
        repo_root
        / constants.GENERATED_DIRNAME
        / constants.GENERATED_ELEMENTS_SUBDIR
        / category
        / local_name
    )
    element_dir.mkdir(parents=True, exist_ok=True)

    (element_dir / constants.GENERATED_ELEMENT_FILENAME).write_text(
        json.dumps(
            {
                "identity": {
                    "compact_id": compact_id,
                }
            }
        ),
        encoding="utf-8",
    )

    return element_dir


def test_generated_element_record_model() -> None:

    record = GeneratedElementRecord(
        category="example",
        name="order",
        rel_dir="data/export/elements/example/order",
        compact_id="ar.example.order",
    )

    assert record.rel_dir == "data/export/elements/example/order"
    assert record.category == "example"
    assert record.name == "order"
    assert record.compact_id == "ar.example.order"


def test_generated_registry_count_and_indexes() -> None:
    record = GeneratedElementRecord(
        category="example",
        name="order",
        rel_dir="data/export/elements/example/order",
        compact_id="ar.example.order",
    )
    registry = GeneratedRegistry(records=(record,))

    assert registry.count == 1
    assert registry.compact_ids() == frozenset({"ar.example.order"})


def test_generated_reconciliation_consistent_when_empty() -> None:
    reconciliation = GeneratedReconciliation()

    assert reconciliation.is_consistent


def test_generated_reconciliation_inconsistent_when_missing_generated() -> None:
    reconciliation = GeneratedReconciliation(
        lock_missing_generated=("ar.example.order",),
    )

    assert not reconciliation.is_consistent


def test_generated_artifact_count_delegates_to_registry() -> None:
    record = GeneratedElementRecord(
        category="example",
        name="order",
        rel_dir="data/export/elements/example/order",
        compact_id="ar.example.order",
    )
    artifact = GeneratedArtifact(
        target_root=".",
        registry=GeneratedRegistry(records=(record,)),
        reconciliation=GeneratedReconciliation(),
    )

    assert artifact.generated_count == 1


def test_collect_generated_elements_missing_export_root_fails(tmp_path: Path) -> None:
    with pytest.raises(StageInputMissing) as exc_info:
        collect_generated_elements(tmp_path)

    assert "data/export" in str(exc_info.value)


def test_collect_generated_elements_returns_empty_without_elements_dir(
    tmp_path: Path,
) -> None:
    export_root = tmp_path / constants.GENERATED_DIRNAME
    export_root.mkdir(parents=True)

    records = collect_generated_elements(tmp_path)

    assert records == []


def test_collect_generated_elements_discovers_element_json(
    tmp_path: Path,
) -> None:
    write_generated_element(
        repo_root=tmp_path,
        category="example",
        local_name="order",
        compact_id="ar.example.order",
    )

    records = collect_generated_elements(tmp_path)

    assert len(records) == 1
    assert records[0].category == "example"
    assert records[0].name == "order"
    assert records[0].rel_dir == "data/export/elements/example/order"
    assert records[0].compact_id == "ar.example.order"


def test_collect_generated_elements_rejects_invalid_json(
    tmp_path: Path,
) -> None:
    artifact_path = (
        tmp_path
        / constants.GENERATED_DIRNAME
        / constants.GENERATED_ELEMENTS_SUBDIR
        / "order"
        / constants.GENERATED_ELEMENT_FILENAME
    )
    artifact_path.parent.mkdir(parents=True, exist_ok=True)
    artifact_path.write_text("{not json", encoding="utf-8")

    with pytest.raises(StageInputMalformed) as exc_info:
        collect_generated_elements(tmp_path)

    assert "invalid JSON" in str(exc_info.value)


def test_collect_generated_elements_rejects_non_object_json(
    tmp_path: Path,
) -> None:
    artifact_path = (
        tmp_path
        / constants.GENERATED_DIRNAME
        / constants.GENERATED_ELEMENTS_SUBDIR
        / "order"
        / constants.GENERATED_ELEMENT_FILENAME
    )
    artifact_path.parent.mkdir(parents=True, exist_ok=True)
    artifact_path.write_text("[]", encoding="utf-8")

    with pytest.raises(StageInputMalformed) as exc_info:
        collect_generated_elements(tmp_path)

    assert "must be a JSON object" in str(exc_info.value)
