"""
SHACL validator -- run pyshacl against ontology data and return a report.
"""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any

from pycharter.wiki.ontology.models import ConceptScheme, OntologyArtifact
from pycharter.wiki.rdf import _check_pyshacl, _check_rdflib


@dataclass
class ShaclReport:
    """Structured result of a SHACL validation run."""

    conforms: bool
    violations: list[dict[str, Any]] = field(default_factory=list)
    raw_text: str = ""


def validate_shacl(data_graph: Any, shapes_graph: Any) -> ShaclReport:
    """
    Run SHACL validation on a data graph against a shapes graph.

    Both arguments must be ``rdflib.Graph`` instances.

    Returns:
        ShaclReport with conformance flag, violations, and raw text.
    """
    _check_pyshacl()
    import pyshacl

    conforms, results_graph, results_text = pyshacl.validate(
        data_graph,
        shacl_graph=shapes_graph,
        inference="none",
        abort_on_first=False,
    )

    violations: list[dict[str, Any]] = []
    if not conforms:
        _check_rdflib()
        from rdflib import RDF, SH

        SH_NS = SH
        for result_node in results_graph.subjects(RDF.type, SH_NS.ValidationResult):
            violation: dict[str, Any] = {}
            for p, o in results_graph.predicate_objects(result_node):
                key = str(p).rsplit("#", 1)[-1].rsplit("/", 1)[-1]
                violation[key] = str(o)
            violations.append(violation)

    return ShaclReport(
        conforms=conforms,
        violations=violations,
        raw_text=results_text,
    )


def validate_ontology_shacl(
    artifact: OntologyArtifact,
    contract_id: str,
    *,
    concepts: ConceptScheme | None = None,
    shapes_path: str | None = None,
) -> ShaclReport:
    """
    High-level: build an RDF graph from the ontology (and optionally the
    concept scheme), load default SHACL shapes, and run validation.

    Args:
        artifact: The field-mapping ontology to validate.
        contract_id: Owning contract identifier.
        concepts: Optional concept scheme (included in data graph for
                  cross-reference checks).
        shapes_path: Override shapes directory (default: built-in shapes).

    Returns:
        ShaclReport with conformance results.
    """
    _check_rdflib()

    from pycharter.wiki.rdf.converter import jsonld_to_graph
    from pycharter.wiki.rdf.emitter import emit_concepts_jsonld, emit_ontology_jsonld
    from pycharter.wiki.rdf.shapes import load_all_shapes

    ontology_doc = emit_ontology_jsonld(artifact, contract_id)
    data_graph = jsonld_to_graph(ontology_doc)

    if concepts is not None:
        concepts_doc = emit_concepts_jsonld(concepts)
        concepts_graph = jsonld_to_graph(concepts_doc)
        data_graph += concepts_graph

    shapes_graph = load_all_shapes(shapes_path)

    return validate_shacl(data_graph, shapes_graph)
