from __future__ import annotations

from typing import Optional

from chemrecon.chem.chemreaction import ChemReaction, chem_reaction_from_rxn
from chemrecon.chem.gml.gml_to_rdk import gml_to_rdkit_reaction
from chemrecon.core.id_types import A_GML_RULE, A_RXN
from chemrecon.schema import (ProceduralGeneratorError, ProceduralRelation, AAMRepr, AAM, )


class AAMConvert(ProceduralRelation[AAMRepr, AAM]):
    """ Standardized and canonical conversion of AAM representations (e.g. reaction SMILES, MolFile, …) into a
        consistent format, stored as a canonical reaction SMILES string.
    """
    # Attributes

    # Database
    entrytype_name = 'AAM Convert'
    _table_name = 'AAMConvert'
    symmetric = False
    source_entrytype = AAMRepr
    target_entrytype = AAM
    _attribute_columns = []
    _index = []

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

    @classmethod
    def generate(
        cls,
        take_entry: AAMRepr
    ) -> list[tuple[ProceduralRelation[AAMRepr, AAM], AAM]]:

        r: Optional[ChemReaction] = None
        try:
            match take_entry.id_type:
                case A_RXN.enum_type:
                    r = chem_reaction_from_rxn(rxn = take_entry.source_id)
                case A_GML_RULE.enum_type:
                    rdk_reaction = gml_to_rdkit_reaction(gml = take_entry.source_id)
                    r = ChemReaction(
                        rdk_reaction = rdk_reaction
                    )
                case _:
                    # Log error and continue
                    raise ProceduralGeneratorError('Cannot create atom-to-atom map for reaction (unsupported format).')
        except Exception as e:
            raise ProceduralGeneratorError(f'Failed converting AAM representation to internal format.') from e
        if r is None:
            raise ProceduralGeneratorError(f'AAM conversion failed.')

        assert take_entry.recon_id is not None
        r_smarts = r.to_reaction_smiles()
        r_entry = AAM(
            reaction_smiles = r_smarts
        )

        # Return AAM
        return [
            (
                AAMConvert(),
                r_entry
            )
        ]
