import logging
import pathlib
from typing import Union

import rdflib
from h5rdmtoolbox.catalog import RDFStore

logger = logging.getLogger("opencefadb")

EXCEPTION_PROPERTIES_NAMESPACES = {
    str(rdflib.OWL),
    str(rdflib.RDF),
    str(rdflib.RDFS),
    str(rdflib.XSD)
}


def _raise_on_blank_nodes(filename: Union[str, pathlib.Path],
                          exception_properties=None) -> rdflib.Graph:
    """Raises an error if the given RDF file contains blank nodes."""
    if exception_properties is None:
        exception_properties = EXCEPTION_PROPERTIES_NAMESPACES
    filename = pathlib.Path(filename).resolve().absolute()
    if not filename.exists():
        raise FileNotFoundError(f"File '{filename}' does not exist")
    temp_graph = rdflib.Graph()
    temp_graph.parse(location=str(filename))

    # Check if there are any blank nodes
    has_blank_nodes = any(
        isinstance(term, rdflib.BNode)
        for triple in temp_graph
        for term in triple
    )
    if has_blank_nodes:
        for s, p, o in temp_graph:
            if isinstance(s, rdflib.BNode) or isinstance(p, rdflib.BNode) or isinstance(o, rdflib.BNode):
                # allow all owl properties:
                for ep in exception_properties:
                    if str(p).startswith(ep):
                        break
                else:
                    raise ValueError(
                        f"File '{filename}' contains blank nodes. Blank nodes are not supported: {s}, {p}, {o}")
    return temp_graph


class LocalRDFStore(RDFStore):
    """A local RDF store using rdflib's in-memory store."""

    def __init__(self):
        self._graph = rdflib.Graph()
        self._expected_file_extensions = {".ttl", ".rdf", ".jsonld"}

    def upload_file(self, filename: Union[str, pathlib.Path]) -> bool:
        """Uploads a file to the local RDF store."""
        _tmp_graph = _raise_on_blank_nodes(filename)
        logger.debug(f"Uploading file {filename} to local RDF store ...")
        self._graph += _tmp_graph
        return True

    @property
    def graph(self) -> rdflib.Graph:
        return self._graph

    def execute_query(self, SELECT_ALL):
        pass

# class GraphDBStore(RDFStore):
#
#     def __init__(
#             self,
#             host,
#             port,
#             user,
#             password,
#             repository
#     ):
#         self._graphdb_url = f"http://{host}:{port}"
#         self._auth = (user, password)
#         _graphdb = GraphDB(
#             url=self._graphdb_url,
#             auth=self._auth
#         )
#         self._host = host
#         self._port = port
#         self._repoID = repository
#         self._repo = _graphdb[repository]
#         self._expected_file_extensions = {".ttl", ".rdf", ".jsonld"}
#
#     def __repr__(self):
#         return f"<{self.__class__.__name__} (GraphDB-Repo={self._repo['id']})>"
#
#     def reset(self, config_filename: Optional[Union[str, pathlib.Path]] = None):
#         logger.debug("Resetting the GraphDB store.")
#         logger.debug("Deleting the GraphDB repo...")
#         self.__class__.delete(
#             self._repoID,
#             self._host,
#             self._port,
#             self._auth
#         )
#         logger.debug("Creating a new GraphDB repo...")
#         self.__class__.create(
#             config_filename,
#             self._host,
#             self._port
#         )
#         logger.debug("...done")
#
#     @classmethod
#     def create(cls,
#                config_filename: Optional[Union[str, pathlib.Path]] = None,
#                host="http://localhost",
#                port=7200):
#         from . import administration
#         if config_filename is None:
#             from opencefadb import GRAPH_DB_CONFIG_FILENAME
#             config_filename = GRAPH_DB_CONFIG_FILENAME
#         repoID = administration.create_repository(
#             config_filename,
#             host,
#             port
#         )
#         return repoID
#
#     @classmethod
#     def delete(cls, repository_id: str, host="http://localhost", port=7200, auth=None):
#         from . import administration
#         if host == "localhost":
#             host = "http://localhost"
#         return administration.delete_repository(
#             repository_id=repository_id,
#             host=host,
#             port=port,
#             auth=auth
#         )
#
#     @property
#     def graph(self) -> rdflib.Graph:
#         return self._repo.graph
#
#     def upload_file(self, filename: Union[str, pathlib.Path]) -> bool:
#         return self._repo.upload_file(filename) == 204
#
#     def execute_query(self, query: SparqlQuery) -> QueryResult:
#         return QueryResult(query=query, result=query.execute(self.graph))


# def _parse_url(url):
#     if url.endswith("/"):
#         return url[:-1]
#     return url
