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

from __future__ import annotations

import pytest

from pycharter.wiki.rdf.context import DEFAULT_BASE_URI, set_base_uri
from pycharter.wiki.rdf.jsonld_parser import (
    parse_concepts_jsonld,
    parse_ontology_jsonld,
)
from pycharter.wiki.shared.errors import OntologyError


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

    def test_basic(self):
        doc = {
            "@context": {},
            "@graph": [
                {
                    "@id": "https://statfyi.com/ontology/scheme/Test",
                    "@type": "skos:ConceptScheme",
                    "prefLabel": "Test",
                    "versionInfo": "1.0.0",
                },
                {
                    "@id": "https://statfyi.com/ontology/concept/Foo",
                    "@type": "skos:Concept",
                    "prefLabel": "Foo Label",
                    "definition": "A foo",
                    "tag": ["t1"],
                },
            ],
        }
        scheme = parse_concepts_jsonld(doc)
        assert scheme.title == "Test"
        assert len(scheme.concepts) == 1
        assert scheme.concepts[0].id == "Foo"
        assert scheme.concepts[0].label == "Foo Label"
        assert scheme.concepts[0].tags == ["t1"]

    def test_broader(self):
        doc = {
            "@graph": [
                {"@type": "skos:ConceptScheme", "prefLabel": "S", "versionInfo": "1"},
                {
                    "@type": "skos:Concept",
                    "@id": "concept/Child",
                    "prefLabel": "Child",
                    "broader": "concept/Parent",
                },
            ],
        }
        scheme = parse_concepts_jsonld(doc)
        assert scheme.concepts[0].broader == "Parent"

    def test_no_scheme_raises(self):
        with pytest.raises(OntologyError):
            parse_concepts_jsonld({"@graph": []})

    def test_not_dict_raises(self):
        with pytest.raises(OntologyError):
            parse_concepts_jsonld([])


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

    def test_basic(self):
        doc = {
            "@graph": [
                {
                    "@id": "contract/order/field/order_id",
                    "@type": "statfyi:FieldMapping",
                    "mapsTo": "concept/OrderIdentifier",
                    "versionInfo": "1.0.0",
                    "tag": ["pk"],
                    "creator": "eng",
                },
            ],
        }
        artifact = parse_ontology_jsonld(doc)
        assert artifact.version == "1.0.0"
        assert "order_id" in artifact.fields
        fo = artifact.fields["order_id"]
        assert fo.concept == "OrderIdentifier"
        assert fo.tags == ["pk"]

    def test_not_dict_raises(self):
        with pytest.raises(OntologyError):
            parse_ontology_jsonld("bad")


class TestParseConceptsNodeKind:
    """Test that nodeKind is parsed from JSON-LD concepts."""

    def setup_method(self):
        set_base_uri(DEFAULT_BASE_URI)

    def test_node_kind_parsed(self):
        doc = {
            "@graph": [
                {"@type": "skos:ConceptScheme", "prefLabel": "S", "versionInfo": "1"},
                {
                    "@type": "skos:Concept",
                    "@id": "concept/Customer",
                    "prefLabel": "Customer",
                    "nodeKind": "entity",
                },
            ],
        }
        scheme = parse_concepts_jsonld(doc)
        assert scheme.concepts[0].node_kind == "entity"

    def test_node_kind_none_when_absent(self):
        doc = {
            "@graph": [
                {"@type": "skos:ConceptScheme", "prefLabel": "S", "versionInfo": "1"},
                {
                    "@type": "skos:Concept",
                    "@id": "concept/Foo",
                    "prefLabel": "Foo",
                },
            ],
        }
        scheme = parse_concepts_jsonld(doc)
        assert scheme.concepts[0].node_kind is None


class TestParseKnowledgeRelationships:
    """Test that new relationship predicates are parsed correctly."""

    def setup_method(self):
        set_base_uri(DEFAULT_BASE_URI)

    def test_depends_on_predicate(self):
        doc = {
            "@graph": [
                {
                    "@id": "contract/test/field/score",
                    "@type": "statfyi:FieldMapping",
                    "mapsTo": "concept/Score",
                    "dependsOn": "contract/test/field/balance",
                },
            ],
        }
        artifact = parse_ontology_jsonld(doc)
        fo = artifact.fields["score"]
        dep_rels = [r for r in fo.relationships if r.type.value == "depends_on"]
        assert len(dep_rels) == 1

    def test_causes_predicate(self):
        doc = {
            "@graph": [
                {
                    "@id": "contract/test/field/trigger",
                    "@type": "statfyi:FieldMapping",
                    "mapsTo": "concept/Trigger",
                    "causes": "contract/test/field/response",
                },
            ],
        }
        artifact = parse_ontology_jsonld(doc)
        fo = artifact.fields["trigger"]
        cause_rels = [r for r in fo.relationships if r.type.value == "causes"]
        assert len(cause_rels) == 1

    def test_governs_predicate(self):
        doc = {
            "@graph": [
                {
                    "@id": "contract/test/field/policy",
                    "@type": "statfyi:FieldMapping",
                    "mapsTo": "concept/Policy",
                    "governs": "contract/test/field/transaction",
                },
            ],
        }
        artifact = parse_ontology_jsonld(doc)
        fo = artifact.fields["policy"]
        gov_rels = [r for r in fo.relationships if r.type.value == "governs"]
        assert len(gov_rels) == 1
