from app.config import Settings, get_settings
from app.docs_repository import DocsRepository
from app.git_adapter import GitAdapter
from app.inventory import InventoryRepository
from app.main import (
    apply_change,
    git_diff,
    git_status,
    health,
    list_docs,
    list_inventory_types,
    read_doc,
    read_change,
    read_inventory,
    read_inventory_item,
    relationships,
    read_traffic_routes,
    validate,
)
from app.pending_changes import PendingChangeRepository, ProposedChangeRequest


def test_health_endpoint() -> None:
    response = health(get_settings())

    assert response["status"] == "ok"


def test_docs_endpoint() -> None:
    response = list_docs(DocsRepository(get_settings()))

    paths = {doc["path"] for doc in response}
    assert "10-systems/hardware/hp-proliant-dl380-g6.md" in paths


def test_read_doc_endpoint() -> None:
    response = read_doc(
        path="10-systems/virtualization/libvirt-vms.md",
        repo=DocsRepository(get_settings()),
    )

    assert response["frontmatter"]["source_of_truth"] == "ssh-libvirt"


def test_inventory_types_endpoint() -> None:
    response = list_inventory_types(InventoryRepository(get_settings()))

    assert "virtual-machines" in response
    assert "traffic-routes" in response


def test_inventory_endpoint() -> None:
    response = read_inventory(
        inventory_type="virtual-machines",
        repo=InventoryRepository(get_settings()),
    )

    assert isinstance(response, list)
    assert len(response) >= 20
    assert any(item["id"] == "gnauth" for item in response)


def test_inventory_item_endpoint() -> None:
    response = read_inventory_item(
        inventory_type="virtual-machines",
        item_id="gnauth",
        repo=InventoryRepository(get_settings()),
    )

    assert response["hypervisor_host"] == "hp-proliant-dl380-g6"


def test_traffic_routes_endpoint() -> None:
    response = read_traffic_routes(InventoryRepository(get_settings()))

    assert response[0]["id"] == "public-gnexus-space-to-internal-nginx"


def test_relationships_endpoint() -> None:
    response = relationships(InventoryRepository(get_settings()))

    assert response["summary"]["node_count"] > 0
    assert {
        "source": "hardware/hp-proliant-dl380-g6",
        "target": "virtual-machines/gnauth",
        "relation": "runs_host",
    } in response["edges"]
    assert {
        "source": "virtual-machines/gnauth",
        "target": "hardware/hp-proliant-dl380-g6",
        "relation": "runs_on",
    } in response["edges"]
    assert {
        "source": "traffic-routes/public-gnexus-space-to-internal-nginx",
        "target": "hosts/external-vps",
        "relation": "entrypoint",
    } in response["edges"]
    assert {
        "source": "traffic-routes/public-gnexus-space-to-internal-nginx",
        "target": "services/internal-nginx-proxy",
        "relation": "destination",
    } in response["edges"]
    assert response["unresolved_references"] == []


def test_validate_endpoint_is_clean() -> None:
    response = validate(get_settings())

    assert response["status"] == "ok"
    assert response["issues"] == []


def test_changes_endpoints(tmp_path) -> None:
    repo = PendingChangeRepository(Settings(tmp_path))
    created = repo.create(
        ProposedChangeRequest(
            kind="doc",
            target="10-systems/example.md",
            summary="Add example doc",
            payload={"content": "# Example"},
        )
    )

    response = read_change(created["id"], repo)

    assert response["id"] == created["id"]
    assert response["kind"] == "doc"


def test_apply_change_rejects_missing_change(tmp_path) -> None:
    repo = PendingChangeRepository(Settings(tmp_path))

    try:
        apply_change("missing", repo)
    except Exception as exc:
        assert "Pending change not found" in str(exc)
    else:
        raise AssertionError("Expected an exception")


def test_git_status_endpoint() -> None:
    response = git_status(GitAdapter(get_settings()))

    assert "entries" in response
    assert "raw" in response


def test_git_diff_endpoint() -> None:
    response = git_diff(None, GitAdapter(get_settings()))

    assert "diff" in response
