from typing import Optional

from chemrecon.schema.enums import SourceDatabase
from chemrecon.schema.db_object import Relation, col_src, InverseRelation
from chemrecon.schema.entry_types.reaction import Reaction


# Is A / Has Instance
# ----------------------------------------------------------------------------------------------------------------------
class ReactionIsA(Relation[Reaction, Reaction]):
    """ Hierarchical relation which indicates that a reaction is a member of a class of reactions.
    """
    # Attributes
    src: SourceDatabase  #: The source of the relation

    # Database
    entrytype_name = 'Is a'
    _table_name = 'ReactionIsA'
    symmetric = False
    source_entrytype = Reaction
    target_entrytype = Reaction
    _attribute_columns = [
        col_src
    ]
    _index = [0]

    def __init__(
            self,
            src: SourceDatabase,
            recon_id_1: Optional[int] = None,
            recon_id_2: Optional[int] = None
    ):
        super().__init__(recon_id_1, recon_id_2)
        self.src = src

    def _vis_str(self) -> str:
        return f'is a'

class ReactionHasInstance(InverseRelation[Reaction, Reaction]):
    """ Hierarchical relation which indicates that a reaction is a member of a class of reactions.
    """
    # Attributes
    src: SourceDatabase  #: The source of the relation

    # Inverse
    inverse_main_relation = ReactionIsA

    # Database
    entrytype_name = 'Has Instance'
    _table_name = 'ReactionHasInstance'
    symmetric = False
    source_entrytype = Reaction
    target_entrytype = Reaction
    _attribute_columns = [
        col_src
    ]
    _index = [0]

    def __init__(
            self,
            src: SourceDatabase,
            recon_id_1: Optional[int] = None,
            recon_id_2: Optional[int] = None
    ):
        super().__init__(recon_id_1, recon_id_2)
        self.src = src

    def _vis_str(self) -> str:
        return f'has instance'

# Set Inverse
ReactionIsA.has_inverse = ReactionHasInstance

# New / Old id
# ----------------------------------------------------------------------------------------------------------------------
class ReactionHasNewID(Relation[Reaction, Reaction]):
    """ Indicates correspondence between identifiers in different database versions. Can be used to resolve deprecated
        identifiers.
    """
    # Attributes
    src: SourceDatabase  #: The source of the relation

    # Database
    entrytype_name = 'Has New ID'
    _table_name = 'ReactionHasNewID'
    symmetric = False
    source_entrytype = Reaction
    target_entrytype = Reaction
    _attribute_columns = [
        col_src
    ]
    _index = [0]

    def __init__(
            self,
            src: SourceDatabase,
            recon_id_1: Optional[int] = None,
            recon_id_2: Optional[int] = None
    ):
        super().__init__(recon_id_1, recon_id_2)
        self.src = src

    def _vis_str(self) -> str:
        return f'new id'

class ReactionHasOldID(InverseRelation[Reaction, Reaction]):
    """ Indicates correspondence between identifiers in different database versions. Can be used to resolve deprecated
        identifiers.
    """
    # Attributes
    src: SourceDatabase  #: The source of the relation

    # Inverse
    inverse_main_relation = ReactionHasNewID

    # Database
    entrytype_name = 'Has Old ID'
    _table_name = 'ReactionHasOldID'
    symmetric = False
    source_entrytype = Reaction
    target_entrytype = Reaction
    _attribute_columns = [
        col_src
    ]
    _index = [0]

    def __init__(
            self,
            src: SourceDatabase,
            recon_id_1: Optional[int] = None,
            recon_id_2: Optional[int] = None
    ):
        super().__init__(recon_id_1, recon_id_2)
        self.src = src

    def _vis_str(self) -> str:
        return f'old id'

# Set Inverse
ReactionHasNewID.has_inverse = ReactionHasOldID
