from relationalai.early_access.dsl.core.relations import AbstractRelation, RelationSignature
from relationalai.early_access.dsl.core.types import AbstractValueType
from relationalai.early_access.dsl.bindings.tables import SubtypeBinding
from relationalai.early_access.dsl.types.entities import EntityType


class GeneratedRelation(AbstractRelation):
    """
    A class representing a relation generated from a model.
    """
    def __init__(self,  namespace, name, sig):
        super().__init__(namespace, name, sig)

    def __repr__(self):
        return f"GeneratedRelation({self.qualified_name()})"

class InternallyGeneratedRelation(GeneratedRelation):
    """
    A class representing a relation generated by analyzing the model.
    """
    def __init__(self,  namespace, name, sig):
        super().__init__(namespace, name, sig)

class RoleMap(InternallyGeneratedRelation):
    """
    A class representing a value map relation.
    """

    def __init__(self, namespace, name, key_type, attr_view, role, functional: bool = False):
        sig = RelationSignature(key_type, role.player(), functional=functional)
        super().__init__(namespace, name, sig)
        self._key_type = key_type
        self._role = role
        self._attr_view = attr_view

    def role(self):
        """
        Returns the role of the value map.
        """
        return self._role

    def value_player(self):
        """
        Returns the value player of the value map.
        """
        return self._role.player()

    def attr_view(self):
        """
        Returns the attribute view of the value map.
        """
        return self._attr_view

    def __repr__(self):
        return f"ValueMap({self.qualified_name()})"

class ValueMap(RoleMap):
    """
    A class representing a value map relation.
    """

    def __init__(self, namespace, name, key_type, attr_view, role):
        super().__init__(namespace, name, key_type, attr_view, role)
        if not isinstance(role.player(), AbstractValueType):
            raise Exception(f"Cannot construct a value map for {role.part_of.pprint()}, concept is not a value type")

    def __repr__(self):
        return f"ValueMap({self.qualified_name()})"

class EntityMap(RoleMap):
    """
    A class representing an entity map relation.
    """

    def __init__(self, namespace, name, key_type, attr_view, role):
        super().__init__(namespace, name, key_type, attr_view, role, functional=True)
        if not isinstance(role.player(), EntityType):
            raise Exception(f"Cannot construct an entity map for {role.part_of.pprint()}, concept is not an entity type")

class EntitySubtypeMap(InternallyGeneratedRelation):
    """
    A class representing an entity subtype map relation.
    """

    def __init__(self, namespace, name, key_type, binding: 'SubtypeBinding'):
        sig = self._get_signature(key_type, binding)
        super().__init__(namespace, name, sig)
        self._key_type = key_type
        self._binding = binding

    @staticmethod
    def _get_signature(key_type, binding: 'SubtypeBinding'):
        subtype = binding.sub_type
        if not isinstance(subtype, EntityType):
            raise Exception(f"Cannot construct an entity subtype map for {subtype.name()}, concept is not an entity type")
        return RelationSignature(key_type, subtype, functional=True)

    def binding(self):
        """
        Returns the binding of the entity subtype map.
        """
        return self._binding

    def subtype(self):
        """
        Returns the subtype of the entity subtype map.
        """
        return self._binding.sub_type

    def attr_view(self):
        """
        Returns the attribute view of the entity subtype map.
        """
        return self._binding.column.relation()
