from typing import Optional

from chemrecon.schema.db_object import Column, Relation, InverseRelation
from chemrecon.schema.entry_types.aam import AAM
from chemrecon.schema.entry_types.molstructure import MolStructure


class AAMInvolvesMolStructure(Relation[AAM, MolStructure]):
    """ Relates the molecular structures involved in an atom-to-atom-mapped reaction.
        These molecular structures are implicitly a part of the AAM structure.
    """
    # Attributes
    side: int  #: The side of the reaction which contains this structure (-1 or 1)
    structure_atom_index_in_aam: list[int]  #: Atom mapping numbers of the atoms in the structure w.r.t. the AAM.

    # Database
    entrytype_name = 'AAM Involves MolStructure'
    _table_name = 'AAMInvolvesMolStructure'
    symmetric = False
    source_entrytype = AAM
    target_entrytype = MolStructure
    _attribute_columns = [
        Column('structure_atom_index_in_aam', list[int])
    ]
    _index = [0]

    def __init__(
        self,
        side: int,
        structure_atom_index_in_aam: list[int],
        recon_id_1: Optional[int] = None,
        recon_id_2: Optional[int] = None
    ):
        super().__init__(recon_id_1, recon_id_2)
        self.side = side
        self.structure_atom_index_in_aam = structure_atom_index_in_aam

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

class MolStructureParticipatesInAAM(InverseRelation[MolStructure, AAM]):
    """ Relates the molecular structures involved in an atom-to-atom-mapped reaction.
        These molecular structures are implicitly a part of the AAM structure.
    """
    # Attributes
    side: int  #: The side of the reaction which contains this structure (-1 or 1)
    structure_atom_index_in_aam: list[int]  #: Atom mapping numbers of the atoms in the structure w.r.t. the AAM.

    # Inverse
    inverse_main_relation = AAMInvolvesMolStructure

    # Database
    entrytype_name = 'MolStructure Participats in AAM'
    _table_name = 'MolStructureParticipatesInAAM'
    symmetric = False
    source_entrytype = MolStructure
    target_entrytype = AAM
    _attribute_columns = [
        Column('structure_atom_index_in_aam', list[int])
    ]
    _index = [0]

    def __init__(
        self,
        side: int,
        structure_atom_index_in_aam: list[int],
        recon_id_1: Optional[int] = None,
        recon_id_2: Optional[int] = None
    ):
        super().__init__(recon_id_1, recon_id_2)
        self.side = side
        self.structure_atom_index_in_aam = structure_atom_index_in_aam

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

AAMInvolvesMolStructure.has_inverse = MolStructureParticipatesInAAM
