from typing import Optional

from chemrecon.schema.db_object import Column, Relation, InverseRelation
from chemrecon.schema.entry_types.aam_repr import AAMRepr
from chemrecon.schema.entry_types.molstructure_repr import MolStructureRepr


class AAMReprInvolvesMolStructureRepr(Relation[AAMRepr, MolStructureRepr]):
    """ Relates the molecular structure representation involved in an atom-to-atom-mapped reaction.
        These molecular structures are implicitly a part of the AAM structure.
    """
    # Attributes
    index: int  #: Index in the mapping string
    stoich: int  #: The stoichiometric coefficient of the MolStructureRepr

    # Database
    entrytype_name = 'AAMRepr Involves MolStructureRepr'
    _table_name = 'AAMReprInvolvesMolStructureRepr'
    symmetric = False
    source_entrytype = AAMRepr
    target_entrytype = MolStructureRepr
    _attribute_columns = [
        Column('index', int),
        Column('stoich', int)
    ]
    _index = [0]

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

    def _vis_str(self) -> str:
        return f'has structure (side: {self.stoich})'

class MolStructureReprParticipatesInAAMRepr(InverseRelation[MolStructureRepr, AAMRepr]):
    """ Relates the molecular structure representation involved in an atom-to-atom-mapped reaction.
        These molecular structures are implicitly a part of the AAM structure.
    """
    # Attributes
    index: int  #: Index in the mapping string
    stoich: int  #: The stoichiometric coefficient of the MolStructureRepr

    # Inverse
    inverse_main_relation = AAMReprInvolvesMolStructureRepr

    # Database
    entrytype_name = 'MolStructureRepr Participates in AAMRepr'
    _table_name = 'MolStructureReprParticipatesInAAMRepr'
    symmetric = False
    source_entrytype = MolStructureRepr
    target_entrytype = AAMRepr
    _attribute_columns = [
        Column('index', int),
        Column('stoich', int)
    ]
    _index = [0]

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

    def _vis_str(self) -> str:
        return f'in aam ({self.stoich})'

AAMReprInvolvesMolStructureRepr.has_inverse = MolStructureReprParticipatesInAAMRepr
