"""Tests for wiki/rdf/emitter.py -- internal models -> JSON-LD."""

from __future__ import annotations

from pycharter.wiki.ontology.models import (
    ConceptDefinition,
    ConceptScheme,
    FieldOntology,
    Lineage,
    OntologyArtifact,
    Relationship,
    RelationshipType,
)
from pycharter.wiki.rdf.context import DEFAULT_BASE_URI, set_base_uri
from pycharter.wiki.rdf.emitter import emit_concepts_jsonld, emit_ontology_jsonld


class TestEmitConceptsJsonld:
    def setup_method(self):
        set_base_uri(DEFAULT_BASE_URI)

    def test_basic_scheme(self):
        scheme = ConceptScheme(
            id="Test",
            title="Test Scheme",
            version="1.0.0",
            concepts=[
                ConceptDefinition(id="Foo", label="Foo Label", definition="A foo"),
                ConceptDefinition(
                    id="Bar", label="Bar Label", broader="Foo", tags=["t1"]
                ),
            ],
        )
        doc = emit_concepts_jsonld(scheme)
        assert "@context" in doc
        assert "@graph" in doc
        graph = doc["@graph"]
        assert len(graph) == 3  # 1 scheme + 2 concepts

        scheme_node = graph[0]
        assert scheme_node["@type"] == "skos:ConceptScheme"
        assert scheme_node["prefLabel"] == "Test Scheme"

        foo_node = graph[1]
        assert "concept/Foo" in foo_node["@id"]
        assert foo_node["prefLabel"] == "Foo Label"

        bar_node = graph[2]
        assert "concept/Foo" in bar_node["broader"]

    def test_deprecated_concept(self):
        scheme = ConceptScheme(
            id="T",
            title="T",
            version="1.0.0",
            concepts=[
                ConceptDefinition(
                    id="Old", label="Old", deprecated=True, replaced_by="New"
                ),
            ],
        )
        doc = emit_concepts_jsonld(scheme)
        node = doc["@graph"][1]
        assert node["deprecated"] is True
        assert "concept/New" in node["isReplacedBy"]


class TestEmitOntologyJsonld:
    def setup_method(self):
        set_base_uri(DEFAULT_BASE_URI)

    def test_basic_mapping(self):
        artifact = OntologyArtifact(
            version="1.0.0",
            fields={
                "order_id": FieldOntology(
                    concept="OrderIdentifier",
                    tags=["pk"],
                    owner="eng",
                ),
            },
        )
        doc = emit_ontology_jsonld(artifact, "order_domain")
        assert "@graph" in doc
        node = doc["@graph"][0]
        assert "concept/OrderIdentifier" in node["mapsTo"]
        assert node["tag"] == ["pk"]
        assert node["creator"] == "eng"

    def test_relationships(self):
        artifact = OntologyArtifact(
            version="1.0.0",
            fields={
                "portfolio_id": FieldOntology(
                    concept="PortfolioIdentifier",
                    relationships=[
                        Relationship(
                            target="portfolio_domain.portfolio_id",
                            type=RelationshipType.REFERENCES,
                        )
                    ],
                ),
            },
        )
        doc = emit_ontology_jsonld(artifact, "cycle_domain")
        node = doc["@graph"][0]
        assert "references" in node
        assert any("portfolio_domain" in r for r in node["references"])

    def test_lineage(self):
        artifact = OntologyArtifact(
            version="1.0.0",
            fields={
                "amount": FieldOntology(
                    concept="MonetaryAmount",
                    lineage=Lineage(derived_from="raw_amount", source_system="billing"),
                ),
            },
        )
        doc = emit_ontology_jsonld(artifact, "billing")
        node = doc["@graph"][0]
        assert "raw_amount" in node["wasDerivedFrom"]
        assert node["wasGeneratedBy"] == "billing"

    def test_knowledge_relationship_types(self):
        """Test that new relationship types emit correct predicates."""
        artifact = OntologyArtifact(
            version="1.0.0",
            fields={
                "risk_score": FieldOntology(
                    concept="RiskScore",
                    relationships=[
                        Relationship(
                            target="metrics.account_balance",
                            type=RelationshipType.DEPENDS_ON,
                        ),
                        Relationship(
                            target="rules.risk_policy",
                            type=RelationshipType.GOVERNS,
                        ),
                    ],
                ),
            },
        )
        doc = emit_ontology_jsonld(artifact, "risk_domain")
        node = doc["@graph"][0]
        assert "dependsOn" in node
        assert "governs" in node

    def test_causes_predicate(self):
        artifact = OntologyArtifact(
            version="1.0.0",
            fields={
                "trigger": FieldOntology(
                    concept="EventTrigger",
                    relationships=[
                        Relationship(
                            target="events.response",
                            type=RelationshipType.CAUSES,
                        ),
                    ],
                ),
            },
        )
        doc = emit_ontology_jsonld(artifact, "event_domain")
        node = doc["@graph"][0]
        assert "causes" in node


class TestEmitConceptsNodeKind:
    """Test that node_kind is emitted correctly in JSON-LD."""

    def setup_method(self):
        set_base_uri(DEFAULT_BASE_URI)

    def test_node_kind_emitted(self):
        scheme = ConceptScheme(
            id="Test",
            title="Test",
            version="1.0.0",
            concepts=[
                ConceptDefinition(
                    id="Customer",
                    label="Customer",
                    node_kind="entity",
                ),
            ],
        )
        doc = emit_concepts_jsonld(scheme)
        node = doc["@graph"][1]
        assert node["nodeKind"] == "entity"

    def test_node_kind_omitted_when_none(self):
        scheme = ConceptScheme(
            id="Test",
            title="Test",
            version="1.0.0",
            concepts=[
                ConceptDefinition(id="Foo", label="Foo"),
            ],
        )
        doc = emit_concepts_jsonld(scheme)
        node = doc["@graph"][1]
        assert "nodeKind" not in node

    def test_multiple_node_kinds(self):
        scheme = ConceptScheme(
            id="Mixed",
            title="Mixed",
            version="1.0.0",
            concepts=[
                ConceptDefinition(id="Cust", label="Customer", node_kind="entity"),
                ConceptDefinition(id="Churn", label="Churn Rate", node_kind="metric"),
                ConceptDefinition(id="Login", label="Login", node_kind="event"),
            ],
        )
        doc = emit_concepts_jsonld(scheme)
        nodes = doc["@graph"][1:]  # skip scheme node
        kinds = [n.get("nodeKind") for n in nodes]
        assert kinds == ["entity", "metric", "event"]
