"""
Core functionality for the paths library.
"""

from relationalai.semantics import Expression, Integer, String, Any
from relationalai.semantics.frontend.base import Library
from relationalai.semantics.frontend.core import Hash

ALLOW_UNIMPLEMENTED = False

def throw_if_not_implemented(msg):
    if not ALLOW_UNIMPLEMENTED:
        raise NotImplementedError(msg)


def path(*args):
    return PathPattern(*args)

class PathPattern:
    def __init__(self, *args):
        self.pattern_exprs = args
        if len(args) == 0:
            raise ValueError("path(...) must have at least one argument.")
        self.filters = []
        self.repeat_count = None

    def where(self, *args):
        throw_if_not_implemented("path(...).where() is not implemented yet.")
        return self

    def repeat(self, min=None, max=None):
        throw_if_not_implemented("path(...).repeat() is not implemented yet.")
        self.repeat_count = (min, max)
        return self

    def all_paths(self):
        return AllPathsTraversalExpr(self)

    def shortest_paths(self):
        return ShortestPathsTraversalExpr(self)

class AbstractPathTraversalExpr(Expression):
    def __init__(self, pattern, semantics):
        self.path_pattern = pattern
        self.semantics = semantics
        throw_if_not_implemented(f"{semantics}_paths() is not implemented yet.")
        # super().__init__(...)

class AllPathsTraversalExpr(AbstractPathTraversalExpr):
    def __init__(self, pattern):
        super().__init__(pattern, "all")

class ShortestPathsTraversalExpr(AbstractPathTraversalExpr):
    def __init__(self, pattern):
        super().__init__(pattern, "shortest")

    def per(self, *args):
        throw_if_not_implemented("shortest_paths().per() is not implemented yet.")
        self.group_by_args = args
        return self

def undirected(expr):
    throw_if_not_implemented("undirected(Concept.relationship) is not implemented yet.")
    return expr

def reverse(expr):
    throw_if_not_implemented("reverse(Concept.relationship) is not implemented yet.")
    return expr

PathsLibrary = Library("paths")
PathTraversal = PathsLibrary.Type("PathTraversal", super_types=[Hash])
PathTraversal.length = PathsLibrary.Property(f"{PathTraversal} is {Integer:length} hops long")
PathTraversal.nodes = PathsLibrary.Relationship(f"{PathTraversal} at {Integer:index} has {Any:concept}")
PathTraversal.relationships = PathsLibrary.Relationship(f"{PathTraversal} at {Integer:index} has {String:relationship}")
PathTraversal.relationship_fields = \
    PathsLibrary.Relationship(f"{PathTraversal} has edge number {Integer:index} with field number {Integer:field_index} and value {Any:field}")
