# -*- coding: UTF-8 -*-
from __future__ import unicode_literals
import re
import json
import itertools
from rdflib import Graph
from rdflib.plugin import register, Serializer

register("json-ld", Serializer, "rdflib_jsonld.serializer", "JsonLDSerializer")


cases = []


def case(*args):
    cases.append(args)


case(
    """
@prefix dcterms: <http://purl.org/dc/terms/> .
<http://example.org/>
    dcterms:title "Homepage"@en .
""",
    {
        "@context": {"@vocab": "http://purl.org/dc/terms/", "@language": "en"},
        "@id": "http://example.org/",
        "title": "Homepage",
    },
)


case(
    """
@prefix dcterms: <http://purl.org/dc/terms/> .
<http://example.org/>
    dcterms:title "Homepage"@en, "Hemsida"@sv .
""",
    {
        "@context": {
            "@vocab": "http://purl.org/dc/terms/",
            "title": {"@container": "@language"},
        },
        "@id": "http://example.org/",
        "title": {"en": "Homepage", "sv": "Hemsida"},
    },
)


case(
    """
@prefix dcterms: <http://purl.org/dc/terms/> .
<http://example.org/>
    dcterms:title "Homepage"@en, "Hemsida"@sv .
""",
    {
        "@context": {
            "@vocab": "http://purl.org/dc/terms/",
            "@language": "sv",
            "title_en": {"@id": "title", "@language": "en"},
        },
        "@id": "http://example.org/",
        "title_en": "Homepage",
        "title": "Hemsida",
    },
)


# .. Requires set values to be sorted to be predictable
# case("""
# @prefix dcterms: <http://purl.org/dc/terms/> .
# <http://example.org/>
#    dcterms:title "Homepage"@en, "Home Page"@en, "Home Page"@en-GB, "Hemsida"@sv .
# """,
# {
#    "@context": "-||-",
#    "@id": "http://example.org/",
#    "title_en": ["Homepage", "Home Page"],
#    "title": [{"@language": "en-GB", "@value": "Home Page"}, "Hemsida"]
# }
# )


case(
    """
@prefix dcterms: <http://purl.org/dc/terms/> .
<http://example.org/easter_island>
    dcterms:title "Påskön"@sv .
""",
    {
        "@context": {"@vocab": "http://purl.org/dc/terms/", "@language": "sv"},
        "@id": "http://example.org/easter_island",
        "title": "Påskön",
    },
)


case(
    """
@prefix : <http://example.org/ns#> .
<http://example.org/> :has _:blank-1 .
""",
    {
        "@context": {"has": {"@type": "@id", "@id": "http://example.org/ns#has"}},
        "@id": "http://example.org/",
        "has": "_:blank-1",
    },
)


case(
    """
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix : <http://example.org/ns#> .
:Something rdfs:subClassOf :Thing .
""",
    {
        "@context": {
            "rdfs": "http://www.w3.org/2000/01/rdf-schema#",
            "v": "http://example.org/ns#",
            "rdfs:subClassOf": {"@container": "@set"},
        },
        "@id": "v:Something",
        "rdfs:subClassOf": [{"@id": "v:Thing"}],
    },
)


case(
    """
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix : <http://example.org/ns#> .
:Something rdfs:subClassOf :Thing .
""",
    {
        "@context": {
            "rdfs": "http://www.w3.org/2000/01/rdf-schema#",
            "v": "http://example.org/ns#",
            "subClassOf": {
                "@id": "rdfs:subClassOf",
                "@type": "@id",
                "@container": "@set",
            },
        },
        "@id": "v:Something",
        "subClassOf": ["v:Thing"],
    },
)


case(
    """
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix : <http://example.org/ns#> .
:World owl:unionOf (:Everyhing :Nothing) .
""",
    {
        "@context": {
            "owl": "http://www.w3.org/2002/07/owl#",
            "v": "http://example.org/ns#",
        },
        "@id": "v:World",
        "owl:unionOf": {"@list": [{"@id": "v:Everyhing"}, {"@id": "v:Nothing"}]},
    },
)


case(
    """
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix : <http://example.org/ns#> .
:World owl:unionOf (:Everyhing :Nothing) .
""",
    {
        "@context": {
            "owl": "http://www.w3.org/2002/07/owl#",
            "v": "http://example.org/ns#",
            "unionOf": {"@id": "owl:unionOf", "@container": "@list"},
        },
        "@id": "v:World",
        "unionOf": [{"@id": "v:Everyhing"}, {"@id": "v:Nothing"}],
    },
)


case(
    """
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix : <http://example.org/ns#> .
:World owl:unionOf (:Everyhing :Nothing) .
""",
    {
        "@context": {
            "owl": "http://www.w3.org/2002/07/owl#",
            "v": "http://example.org/ns#",
            "unionOf": {"@id": "owl:unionOf", "@type": "@id", "@container": "@list"},
        },
        "@id": "v:World",
        "unionOf": ["v:Everyhing", "v:Nothing"],
    },
)


# Shorten result IRIs by using @base
case(
    """
BASE <http://example.org/>
PREFIX : <http://example.org/vocab/>
<Thing> a :Class .
<Work> a :Class; :subClassOf <Thing> .
</some/path/> a :Thing .
</some/path/#this> a :Thing .
</some/path/#other> a :Thing .
""",
    {
        "@context": {
            "@base": "http://example.org/some/path/#other",
            "@vocab": "http://example.org/vocab/",
        },
        "@graph": [
            {"@id": "/Thing", "@type": "Class"},
            {"@id": "/Work", "@type": "Class", "subClassOf": {"@id": "/Thing"}},
            {"@id": "", "@type": "Thing"},
            {"@id": "/some/path/#this", "@type": "Thing"},
            {"@id": "/some/path/#other", "@type": "Thing"},
        ],
    },
)


json_kwargs = dict(indent=2, separators=(",", ": "), sort_keys=True, ensure_ascii=False)


def run(data, expected):
    g = Graph().parse(data=data, format="turtle")
    result = g.serialize(format="json-ld", context=expected["@context"])
    if isinstance(result, bytes):
        result = result.decode("utf-8")
    result = json.loads(result)

    sort_graph(result)
    result = json.dumps(result, **json_kwargs)
    incr = itertools.count(1)
    result = re.sub(r'"_:[^"]+"', lambda m: '"_:blank-%s"' % next(incr), result)

    sort_graph(expected)
    expected = json.dumps(expected, **json_kwargs)

    assert result == expected, "Expected not equal to result: %s" % result


def sort_graph(data):
    if "@graph" in data:
        data["@graph"].sort(key=lambda node: node.get("@id"))


def test_cases():
    for data, expected in cases:
        yield run, data, expected
