from pylindas.pyshareddimension import SharedDimension
from rdflib import Graph
import pandas as pd
import pytest
import yaml

class TestClass:

    TEST_CASE_PATH = "example/Shared_Dimensions/"

    @classmethod
    def setup_test_shared_dimension(cls, dataframe_path: str, description_path: str) -> SharedDimension:
        with open(cls.TEST_CASE_PATH + description_path) as file:
            description = yaml.safe_load(file)
        dataframe = pd.read_csv(cls.TEST_CASE_PATH + dataframe_path, sep=";")
        sd = SharedDimension(dataframe=dataframe, sd_yaml=description, environment="TEST", local=True)
        return sd.prepare_data().write_sd().write_terms()

    def setup_method(self):
        self.shared_dimension = self.setup_test_shared_dimension(
            "shared_dimension_generation/sd_terms.csv", "shared_dimension_generation/sd_description.yml")

    # SHACL validation of the Shared Dimension
    #   Please see the comment of the SharedDimension.validate() method
    #   in order to understand the parameters
    # This is work in progress as the SHACL file has to be passed as parameter instead of being downloaded from the Web behind the scene
    def test_perform_SHACL_validation(self):
        result_bool, result_message = self.shared_dimension.validate("./pylindas/pyshareddimension/shared_dimension_shape.ttl")
        assert result_bool == True        

    # Test some basic triples of the shared dimension
    # Will better be done by the SHACL validation
    # However, this allows to test that triples that might be optional for SHACL are correctly generated in the example
    #   as for instance schema:validFrom
    def test_shared_dimension_triples(self):
        sparql = (
            "PREFIX meta: <https://cube.link/meta/>"
            "PREFIX schema: <http://schema.org/>"
            "PREFIX dct: <http://purl.org/dc/terms/>"
            "ASK"
            "{"
            "  ?sd a meta:SharedDimension, schema:DefinedTermSet ;"
            "     schema:name ?name ;"
            "     schema:description ?desc ;"
            "     schema:identifier ?identifier ;"
            "     dct:contributor/schema:email ?contributorEmail ;"
            "     dct:contributor/schema:name ?contributorName ;"
            "     schema:validFrom ?validFrom"
            "}"
        )

        result = self.shared_dimension._graph.query(sparql)
        assert bool(result)

    def test_shared_dimension_unwanted_triples(self):
        # A Shared dimension generated by code should not have the rdf:type:
        #   hydra:Resource, md:SharedDimension
        # Those types are given to shared dimensions generated from the Cube Creator
        # When generated by code, the shared dimension should marked 'read-only' in the Cube Creator
        #   and this is achieved by not having those 2 types
        sparql = (
            "PREFIX meta: <https://cube.link/meta/>"
            "PREFIX md: <https://cube-creator.zazuko.com/shared-dimensions/vocab#>"
            "PREFIX hydra: <https://www.w3.org/ns/hydra/core#>"
            "ASK"
            "{"
            "  ?sd a meta:SharedDimension,"
            "      hydra:Resource, md:SharedDimension"
            "}"
        )

        result = self.shared_dimension._graph.query(sparql)
        # assert that NO result is found
        assert not bool(result)        
        

    def test_shared_dimension_terms(self):
        # Find terms that are missing some triples
        sparql = (
            "PREFIX meta: <https://cube.link/meta/>"
            "PREFIX schema: <http://schema.org/>"
            "PREFIX md: <https://cube-creator.zazuko.com/shared-dimensions/vocab#>"
            "PREFIX hydra: <https://www.w3.org/ns/hydra/core#>"
            "PREFIX sd_md: <https://cube-creator.zazuko.com/shared-dimensions/vocab#>"
            "ASK"
            "{"
            "  ?sd a schema:DefinedTerm, sd_md:SharedDimensionTerm ."
            "   FILTER NOT EXISTS {?sd schema:identifier ?id;"
            "       schema:inDefinedTermSet <https://ld.admin.ch/cube/dimension/pylindas_sd_generation_example> ;"
            "       schema:name ?name ;"
            "       schema:validFrom ?validFrom ;"
            "   }"
            "}"
        )

        result = self.shared_dimension._graph.query(sparql)
        # There should be no term missing those triples
        assert not bool(result)        
        
    def test_shared_dimension_one_single_root(self):
        # In that example, there should be only one terme with no parent (skos:broader)
        sparql = (
            "PREFIX schema: <http://schema.org/>"
            "PREFIX sd_md: <https://cube-creator.zazuko.com/shared-dimensions/vocab#>"
            "PREFIX skos: <http://www.w3.org/2004/02/skos/core#>"
            "SELECT *"
            "{"
            "  ?sd a schema:DefinedTerm, sd_md:SharedDimensionTerm ."
            "   FILTER NOT EXISTS {?sd skos:broader ?parent}"
            "}"
        )

        result = self.shared_dimension._graph.query(sparql)
        # There should be only one result
        assert len(list(result)) == 1