from __future__ import annotations

import json
from pathlib import Path

from rdflib import Dataset

from cf_pipeline_report.cli import render_report_artifacts
from cf_pipeline_report.manifest import resolve_manifest_paths
from cf_pipeline_report.renderer import build_report_payload


CANONICAL_CF_NS = "https://cogniflow.odea-project.org/cf#"
LEGACY_CF_NS = "https://cogniflow.odea-project.org/cf#"
_STRUCTURED_SUFFIX = "." + "json" + "ld"
_STRUCTURED_FORMAT = "json" + "-ld"


def _pipeline_document(cf_ns: str) -> dict:
    return {
        "@context": {
            "cf": cf_ns,
            "schema": "https://schema.org/",
        },
        "@graph": [
            {
                "@id": "urn:report:test",
                "@type": "cf:Report",
                "cf:reportForPipeline": {"@id": "urn:pipeline:test"},
            },
            {
                "@id": "urn:pipeline:test",
                "@type": "cf:ProcessingPipeline",
                "cf:hasPipelineNode": [{"@id": "urn:node:1"}],
            },
            {
                "@id": "urn:node:1",
                "@type": "cf:PipelineNode",
                "schema:position": 1,
                "cf:nodeDefinition": {"@id": f"{cf_ns}DemoStep"},
            },
        ],
    }


def _write_manifest(path: Path, document: dict) -> Path:
    if path.suffix.lower() in {_STRUCTURED_SUFFIX, ".json"}:
        path.write_text(json.dumps(document, indent=2), encoding="utf-8")
        return path

    dataset = Dataset()
    dataset.parse(data=json.dumps(document), format=_STRUCTURED_FORMAT)
    payload = dataset.serialize(format="nquads")
    if isinstance(payload, bytes):
        payload = payload.decode("utf-8")
    path.write_text(payload, encoding="utf-8")
    return path


def test_build_report_payload_accepts_canonical_nquads_manifest(tmp_path: Path) -> None:
    manifest_path = _write_manifest(
        tmp_path / "demo_pipeline.nq",
        _pipeline_document(CANONICAL_CF_NS),
    )

    payload = build_report_payload(str(manifest_path))

    assert payload["pipeline"]["pipeline_uri"] == "urn:pipeline:test"
    assert len(payload["pipeline"]["nodes"]) == 1
    assert payload["pipeline"]["nodes"][0]["definition_uri"] == f"{CANONICAL_CF_NS}DemoStep"


def test_build_report_payload_keeps_structured_manifest_readable(tmp_path: Path) -> None:
    manifest_path = _write_manifest(
        tmp_path / "demo_pipeline.json",
        _pipeline_document(LEGACY_CF_NS),
    )

    payload = build_report_payload(str(manifest_path))

    assert payload["report"]["pipeline_uri"] == "urn:pipeline:test"
    assert payload["pipeline"]["nodes"][0]["definition_uri"] == f"{LEGACY_CF_NS}DemoStep"


def test_render_report_artifacts_accepts_nquads_manifest(tmp_path: Path) -> None:
    manifest_path = _write_manifest(
        tmp_path / "demo_pipeline.nq",
        _pipeline_document(CANONICAL_CF_NS),
    )

    html_path, data_path = render_report_artifacts(str(manifest_path))

    assert html_path.exists()
    assert data_path.exists()
    payload = json.loads(data_path.read_text(encoding="utf-8"))
    assert payload["pipeline"]["pipeline_uri"] == "urn:pipeline:test"


def test_resolve_manifest_paths_includes_nquads(tmp_path: Path) -> None:
    manifest_nq = _write_manifest(
        tmp_path / "one.nq",
        _pipeline_document(CANONICAL_CF_NS),
    )
    manifest_nquads = _write_manifest(
        tmp_path / "two.nquads",
        _pipeline_document(CANONICAL_CF_NS),
    )

    resolved = resolve_manifest_paths(tmp_path)

    assert manifest_nq in resolved
    assert manifest_nquads in resolved