import io
import time
from pathlib import Path
from textwrap import dedent

import httpx
import pytest
from git import Repo
from rdflib import RDF, SKOS, Graph, Literal, URIRef
from rdflib.query import Result

from prezmanifest.event.client import DeltaEventClient
from prezmanifest.event.syncer import _rdf_patch_body_substr, sync_rdf_delta


@pytest.fixture
def repo(tmp_path: Path):
    repo_url = "https://github.com/Kurrawong/prezmanifest.git"
    repo = Repo.clone_from(repo_url, tmp_path)
    assert repo.working_tree_dir
    assert repo.working_dir == str(tmp_path)
    print(tmp_path)
    assert (tmp_path / ".git").exists()
    yield repo


def query(
    query: str, sparql_endpoint: str, http_client: httpx.Client, headers: dict[str, str]
) -> Result:
    response = http_client.post(
        sparql_endpoint,
        headers={"Content-Type": "application/sparql-query", **headers},
        content=query,
    )
    response.raise_for_status()
    return Result.parse(
        io.BytesIO(response.content), response.headers["Content-Type"].split(";")[0]
    )


def test(
    repo: Repo,
    sparql_endpoint: str,
    http_client: httpx.Client,
    client: DeltaEventClient,
):
    cwd = Path(repo.working_tree_dir)
    previous_commit = "35038026eb98feca22042c4a0ef7ddcdc6a1a5c1"

    # Load the "old" state from the previous commit.
    # Nothing exists yet, so this will perform a full load.
    repo.git.checkout(previous_commit)
    sync_rdf_delta(
        cwd,
        cwd / "tests/demo-vocabs/manifest.ttl",
        sparql_endpoint=sparql_endpoint,
        http_client=http_client,
        event_client=client,
    )

    # We haven't changed the state of the repo.
    # Calling sync_rdf_delta again should do nothing.
    sync_rdf_delta(
        cwd,
        cwd / "tests/demo-vocabs/manifest.ttl",
        sparql_endpoint=sparql_endpoint,
        http_client=http_client,
        event_client=client,
    )

    # This is the second patch log created, that's why the log id is 2.
    log = client._inner.get_log(2, "ds")
    # No statements were added or deleted.
    assert "TX .\nTC ." in log

    # We make some changes to the resources in the manifest.
    image_test_vocab_file = cwd / "tests/demo-vocabs/vocabs/image-test.ttl"
    graph = Graph().parse(image_test_vocab_file)
    # Delete apron-image.
    apron_image = URIRef("https://example.com/demo-vocabs/image-test/apron-image")
    graph.remove((apron_image, None, None))
    graph.remove((None, None, apron_image))
    # Add a new dog-image.
    concept_scheme = URIRef("https://example.com/demo-vocabs/image-test")
    dog_image = URIRef("https://example.com/demo-vocabs/image-test/dog-image")
    graph.add((concept_scheme, SKOS.hasTopConcept, dog_image))
    graph.add((dog_image, RDF.type, SKOS.Concept))
    graph.add((dog_image, SKOS.inScheme, concept_scheme))
    graph.add((dog_image, SKOS.prefLabel, Literal("Dog Image", lang="en")))
    graph.add((dog_image, SKOS.definition, Literal("A dog image")))
    graph.serialize(image_test_vocab_file, format="turtle")

    # We create a new commit. This becomes the "latest" commit.
    repo.index.add([image_test_vocab_file])
    repo.index.commit("Removed apron-image and added dog-image to image-test vocab.")
    # Now calling sync_rdf_delta should generate a patch log with the following expected changes.
    sync_rdf_delta(
        cwd,
        cwd / "tests/demo-vocabs/manifest.ttl",
        sparql_endpoint=sparql_endpoint,
        http_client=http_client,
        event_client=client,
    )

    # Sleep to allow RDF Delta to sync
    time.sleep(0.5)
    # apron-image is now deleted.
    response = query(
        "DESCRIBE <https://example.com/demo-vocabs/image-test/apron-image>",
        sparql_endpoint,
        http_client,
        {"Accept": "application/n-triples"},
    )
    assert len(response.graph) == 0
    # dog-image is now added.
    response = query(
        "SELECT * WHERE { GRAPH ?g { <https://example.com/demo-vocabs/image-test/dog-image> ?p ?o } }",
        sparql_endpoint,
        http_client,
        {"Accept": "application/sparql-results+json"},
    )
    assert len(response.bindings) == 4
    # This is the third patch
    log = client._inner.get_log(3, "ds")
    log_body = "".join(_rdf_patch_body_substr(log))
    log_body = log_body.replace(r"\"", '"')
    # Sort and strip out the first statement, which is the git commit version.
    # The value here is different each time as it's generated by git, so strip it out
    # before we perform a comparison.
    log_body = sorted(log_body.split("\n"))[1:]
    log_body = "\n".join(log_body)
    expected_log_body = dedent("""\
TX .
A <_:b0> <https://schema.org/value> "10a681f1aa65a72b8ed660b904c62d30486fe528" <https://olis.dev/SystemGraph> .
A <https://example.com/demo-vocabs/image-test/dog-image> <http://www.w3.org/2004/02/skos/core#inScheme> <https://example.com/demo-vocabs/image-test> <https://example.com/demo-vocabs/image-test> .
A <https://example.com/demo-vocabs/image-test/dog-image> <http://www.w3.org/2004/02/skos/core#definition> "A dog image" <https://example.com/demo-vocabs/image-test> .
A <https://example.com/demo-vocabs/image-test/dog-image> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2004/02/skos/core#Concept> <https://example.com/demo-vocabs/image-test> .
A <https://example.com/demo-vocabs/image-test/dog-image> <http://www.w3.org/2004/02/skos/core#prefLabel> "Dog Image"@en <https://example.com/demo-vocabs/image-test> .
A <https://example.com/demo-vocabs/image-test> <http://www.w3.org/2004/02/skos/core#hasTopConcept> <https://example.com/demo-vocabs/image-test/dog-image> <https://example.com/demo-vocabs/image-test> .
D <_:b0> <https://schema.org/value> "35038026eb98feca22042c4a0ef7ddcdc6a1a5c1" <https://olis.dev/SystemGraph> .
D <https://example.com/demo-vocabs/image-test/apron-image> <http://www.w3.org/2004/02/skos/core#inScheme> <https://example.com/demo-vocabs/image-test> <https://example.com/demo-vocabs/image-test> .
D <https://example.com/demo-vocabs/image-test/apron-image> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2004/02/skos/core#Concept> <https://example.com/demo-vocabs/image-test> .
D <https://example.com/demo-vocabs/image-test/apron-image> <https://schema.org/image> "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" xmlns:sodipodi=\"http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd\" xmlns:svg=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"97.118958mm\" height=\"74.286232mm\" viewBox=\"0 0 97.118957 74.286232\" version=\"1.1\" id=\"svg5\" xml:space=\"preserve\" inkscape:version=\"1.2.2 (b0a8486, 2022-12-01)\" sodipodi:docname=\"apron.inkscape.svg\" inkscape:export-filename=\"apron.png\" inkscape:export-xdpi=\"96\" inkscape:export-ydpi=\"96\"><sodipodi:namedview id=\"namedview7\" pagecolor=\"#ffffff\" bordercolor=\"#666666\" borderopacity=\"1.0\" inkscape:showpageshadow=\"2\" inkscape:pageopacity=\"1\" inkscape:pagecheckerboard=\"0\" inkscape:deskcolor=\"#ffffff\" inkscape:document-units=\"mm\" showgrid=\"false\" inkscape:zoom=\"1.8380915\" inkscape:cx=\"75.077873\" inkscape:cy=\"204.01596\" inkscape:window-width=\"2063\" inkscape:window-height=\"1210\" inkscape:window-x=\"133\" inkscape:window-y=\"70\" inkscape:window-maximized=\"0\" inkscape:current-layer=\"layer1\" /><defs id=\"defs2\"><linearGradient inkscape:collect=\"always\" id=\"linearGradient3584\"><stop style=\"stop-color:#808080;stop-opacity:1;\" offset=\"0\" id=\"stop3580\" /><stop style=\"stop-color:#808080;stop-opacity:0;\" offset=\"1\" id=\"stop3582\" /></linearGradient><linearGradient inkscape:collect=\"always\" id=\"linearGradient3522\"><stop style=\"stop-color:#ffffff;stop-opacity:1;\" offset=\"0\" id=\"stop3518\" /><stop style=\"stop-color:#ffffff;stop-opacity:0;\" offset=\"1\" id=\"stop3520\" /></linearGradient><linearGradient inkscape:collect=\"always\" xlink:href=\"#linearGradient3522\" id=\"linearGradient3524\" x1=\"64.030418\" y1=\"96.847031\" x2=\"143.43111\" y2=\"96.847031\" gradientUnits=\"userSpaceOnUse\" /><linearGradient inkscape:collect=\"always\" xlink:href=\"#linearGradient3584\" id=\"linearGradient3586\" x1=\"67.60627\" y1=\"98.366364\" x2=\"148.15862\" y2=\"98.366364\" gradientUnits=\"userSpaceOnUse\" /></defs><g inkscape:label=\"img-top\" inkscape:groupmode=\"layer\" id=\"layer1\" style=\"display:inline\" transform=\"translate(-53.17203,-43.635959)\"><text xml:space=\"preserve\" style=\"font-size:4.93889px;line-height:0.95;font-family:sans-serif;display:inline;stroke-width:0.264583\" x=\"145.31673\" y=\"68.72187\" id=\"text364\" inkscape:label=\"A'\"><tspan sodipodi:role=\"line\" id=\"tspan362\" style=\"font-size:4.93889px;stroke-width:0.264583\" x=\"145.31673\" y=\"68.72187\">A'</tspan></text><text xml:space=\"preserve\" style=\"font-size:4.93889px;line-height:0.95;font-family:sans-serif;display:inline;stroke-width:0.264583\" x=\"53.109329\" y=\"69.1222\" id=\"text356\" inkscape:label=\"A\"><tspan sodipodi:role=\"line\" id=\"tspan354\" style=\"font-size:4.93889px;stroke-width:0.264583\" x=\"53.109329\" y=\"69.1222\">A</tspan></text><path style=\"fill:none;stroke:#0000ff;stroke-width:0.265;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1\" d=\"m 57.779747,66.186502 6.271707,0.13344 m 10.942123,-5.20418 c 3.257361,-3.824489 5.768834,-16.591931 11.876208,-17.347268 l 31.491965,0.13344 c 9.02277,0.304639 8.97067,10.773129 12.27653,17.480709\" id=\"path521\" sodipodi:nodetypes=\"cccccc\" inkscape:label=\"line thin\" /><path style=\"fill:none;stroke:#0000ff;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1\" d=\"m 140.51287,66.186502 3.20258,-0.13344\" id=\"path523\" inkscape:label=\"line thin\" /><path style=\"display:inline;fill:none;stroke:#0000ff;stroke-width:1.065;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1\" d=\"m 64.37479,66.27375 c 3.51625,-2.756604 7.149616,-4.459157 10.919028,-4.937299\" id=\"path1153\" sodipodi:nodetypes=\"cc\" inkscape:label=\"line thick\" /><path style=\"display:inline;fill:none;stroke:#0000ff;stroke-width:1.065;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1\" d=\"m 130.64854,61.051609 c 2.69577,3.040226 5.97672,4.617491 9.6847,5.127193\" id=\"path1155\" sodipodi:nodetypes=\"cc\" inkscape:label=\"line thick\" /><ellipse style=\"fill:#0000ff;stroke:#0000ff;stroke-width:1.065;stroke-dasharray:none;paint-order:fill markers stroke;stop-color:#000000\" id=\"path1209\" cx=\"64.327316\" cy=\"66.178802\" rx=\"0.4272663\" ry=\"0.37979227\" inkscape:label=\"dot\" /><ellipse style=\"fill:#0000ff;stroke:#0000ff;stroke-width:1.065;stroke-dasharray:none;paint-order:fill markers stroke;stop-color:#000000\" id=\"path1209-8\" cx=\"74.914024\" cy=\"61.241501\" rx=\"0.4272663\" ry=\"0.37979227\" inkscape:label=\"dot\" /><ellipse style=\"fill:#0000ff;stroke:#0000ff;stroke-width:1.065;stroke-dasharray:none;paint-order:fill markers stroke;stop-color:#000000\" id=\"path1209-6\" cx=\"130.64854\" cy=\"61.241505\" rx=\"0.4272663\" ry=\"0.37979227\" inkscape:label=\"dot\" /><ellipse style=\"display:inline;fill:#0000ff;stroke:#0000ff;stroke-width:1.065;stroke-dasharray:none;paint-order:fill markers stroke;stop-color:#000000\" id=\"path1209-7\" cx=\"140.61809\" cy=\"66.463654\" rx=\"0.4272663\" ry=\"0.37979227\" inkscape:label=\"dot\" /></g><g inkscape:groupmode=\"layer\" id=\"layer2\" inkscape:label=\"img-bottom\" transform=\"translate(-53.17203,-43.635959)\"><text xml:space=\"preserve\" style=\"font-size:4.93889px;line-height:0.95;font-family:sans-serif;display:inline;stroke-width:0.264583\" x=\"145.98393\" y=\"89.004837\" id=\"text418\" inkscape:label=\"A'\"><tspan sodipodi:role=\"line\" id=\"tspan416\" style=\"font-size:4.93889px;stroke-width:0.264583\" x=\"145.98393\" y=\"89.004837\">A'</tspan></text><text xml:space=\"preserve\" style=\"font-size:4.93889px;line-height:0.95;font-family:sans-serif;stroke-width:0.264583\" x=\"58.580395\" y=\"107.41962\" id=\"text360\" inkscape:label=\"A\"><tspan sodipodi:role=\"line\" id=\"tspan358\" style=\"font-size:4.93889px;stroke-width:0.264583\" x=\"58.580395\" y=\"107.41962\">A</tspan></text><path style=\"display:inline;fill:url(#linearGradient3586);fill-opacity:1;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:1.05833, 0.529166;stroke-dashoffset:0;stroke-opacity:1\" d=\"m 67.792919,103.20855 c 4.599387,-9.503289 12.289063,-18.282292 32.946981,-24.021863 12.12077,-1.108928 23.16637,1.62207 33.51667,6.836262 l 7.78574,4.082767 c 5.60824,7.500866 6.29687,9.877152 5.88678,11.108924 -3.26483,7.38071 -7.18384,7.23836 -10.91903,9.20996 -10.4388,5.06006 -20.66991,6.38166 -30.85812,6.93121 -8.988417,1.01278 -17.470444,0.2532 -25.446082,-2.27875 -3.993675,-1.7923 -8.342705,-2.87389 -11.393767,-6.55142 -0.969389,-1.49456 -1.797623,-3.07382 -1.519172,-5.31709 z\" id=\"path1315\" sodipodi:nodetypes=\"cccccccccc\" /><path style=\"fill:#ffffff;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:1.05833, 0.529166;stroke-dashoffset:0;stroke-opacity:1\" d=\"m 77.002882,98.84094 7.026159,-6.361523 c 6.083988,-5.950949 11.770322,-8.985769 17.280549,-10.729132 7.06531,-0.658765 14.47992,0.42898 22.31279,3.608028 3.72737,1.172182 6.59804,3.415237 9.58976,5.506987 2.25277,2.747834 5.17529,4.825911 7.97564,7.026159 1.78653,2.133421 1.66729,3.949211 0,5.506991 -5.84246,3.73718 -11.81949,7.17831 -18.60982,8.83017 -4.73149,1.40464 -9.60474,2.49032 -15.09675,2.1838 -4.68506,0.4466 -8.787537,-1.24294 -12.912934,-2.84844 -3.291533,-1.31082 -6.583066,-2.39442 -9.874599,-2.5636 -2.973433,-0.1711 -5.85874,-1.04722 -8.640276,-2.75349 -0.801585,-2.11557 -1.789119,-4.17242 0.949481,-7.40595 z\" id=\"path1313\" sodipodi:nodetypes=\"ccccccccccccc\" /><path style=\"fill:none;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:1.05833, 0.529166;stroke-dashoffset:0;stroke-opacity:1\" d=\"m 80.326065,98.366198 5.317093,-4.367612 9.589754,-6.36152 9.304908,-3.323183 c 6.87816,-0.02477 12.86259,1.55916 18.79972,3.228235 3.15956,1.049802 5.56485,2.853877 7.97564,4.652457 l 8.35543,6.36152 c 1.08339,1.20359 0.597,2.210955 0.18989,3.228235 -5.75066,4.27882 -11.03758,5.77526 -16.42601,7.88069 -5.95586,1.84631 -11.51884,2.25204 -16.90076,1.99391 -4.43091,-0.61103 -8.861819,-1.94866 -13.292729,-3.51308 -3.048129,-1.29307 -6.066741,-2.40904 -8.925118,-2.5636 -2.056026,-0.26064 -4.013977,-0.70108 -4.937299,-3.03834 -0.0801,-1.26037 0.477077,-2.733171 0.949481,-4.177712 z\" id=\"path1311\" sodipodi:nodetypes=\"cccccccccccccc\" /><path style=\"display:inline;fill:none;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:1.05833, 0.529166;stroke-dashoffset:0;stroke-opacity:1\" d=\"m 83.459351,97.701562 6.836261,-4.082767 c 5.777343,-4.396213 9.074888,-4.659428 13.292728,-6.456468 6.61438,-0.124928 12.94692,1.15935 19.17951,2.943389 3.01596,1.078699 4.8098,2.646247 6.93121,4.082767 2.75815,1.611792 5.31325,3.325107 6.93121,5.506989 -0.34477,2.947598 -9.78734,6.397208 -15.85633,7.785738 -3.89858,0.98424 -7.87315,1.58855 -11.96346,1.61412 -5.18319,-0.71088 -10.546343,-1.06185 -15.001788,-3.22823 -1.726601,-0.57796 -3.163168,-1.54263 -5.412042,-1.42422 l -4.082767,-0.75959 c -1.426529,-0.31511 -1.879655,-1.21426 -2.373701,-2.08886 0.398131,-1.838918 0.929823,-3.010025 1.519169,-3.892868 z\" id=\"path1309\" sodipodi:nodetypes=\"ccccccccccccc\" /><path style=\"display:inline;fill:url(#linearGradient3524);fill-opacity:1;stroke:#0000ff;stroke-width:0.565;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:2.825;stroke-dashoffset:0;stroke-opacity:1\" d=\"M 64.089946,105.39236 143.37158,88.301702\" id=\"path1301\" inkscape:label=\"line\" /></g></svg>"@en <https://example.com/demo-vocabs/image-test> .
D <https://example.com/demo-vocabs/image-test/apron-image> <http://www.w3.org/2004/02/skos/core#prefLabel> "Apron"@en <https://example.com/demo-vocabs/image-test> .
D <https://example.com/demo-vocabs/image-test> <http://www.w3.org/2004/02/skos/core#hasTopConcept> <https://example.com/demo-vocabs/image-test/apron-image> <https://example.com/demo-vocabs/image-test> .
D <https://example.com/demo-vocabs/image-test/apron-image> <http://www.w3.org/2004/02/skos/core#definition> "Here is where we give the definition of an Apron, in words" <https://example.com/demo-vocabs/image-test> .
TC .
    """).strip()
    expected_log_body = sorted(expected_log_body.split("\n"))[1:]
    expected_log_body = "\n".join(expected_log_body)
    # The patch body matches.
    assert log_body == expected_log_body
