from rdkit import Chem

from macro_lactone_toolkit import MacrolactoneFragmenter

from .helpers import build_macrolactone


def test_fragmentation_returns_empty_list_without_sidechains():
    built = build_macrolactone(12)
    result = MacrolactoneFragmenter().fragment_molecule(built.smiles, parent_id="plain")

    assert result.fragments == []


def test_fragmentation_emits_labeled_and_plain_smiles_round_trip():
    built = build_macrolactone(16, {5: "ethyl", 8: "methyl"})
    result = MacrolactoneFragmenter().fragment_molecule(built.smiles, parent_id="mol_001")

    assert result.parent_id == "mol_001"
    assert result.ring_size == 16
    assert {fragment.cleavage_position for fragment in result.fragments} == {5, 8}

    for fragment in result.fragments:
        labeled = Chem.MolFromSmiles(fragment.fragment_smiles_labeled)
        plain = Chem.MolFromSmiles(fragment.fragment_smiles_plain)

        assert labeled is not None
        assert plain is not None
        assert Chem.MolToSmiles(labeled, isomericSmiles=True)
        assert Chem.MolToSmiles(plain, isomericSmiles=True)
        assert any(
            atom.GetAtomicNum() == 0 and atom.GetIsotope() == fragment.cleavage_position
            for atom in labeled.GetAtoms()
        )
        assert any(
            atom.GetAtomicNum() == 0 and atom.GetIsotope() == 0
            for atom in plain.GetAtoms()
        )


def test_fragmentation_preserves_attachment_bond_type():
    built = build_macrolactone(16, {6: "exocyclic_alkene"})
    result = MacrolactoneFragmenter().fragment_molecule(built.smiles, parent_id="bond_type")

    fragment = next(fragment for fragment in result.fragments if fragment.cleavage_position == 6)
    labeled = Chem.MolFromSmiles(fragment.fragment_smiles_labeled)
    plain = Chem.MolFromSmiles(fragment.fragment_smiles_plain)

    for mol in (labeled, plain):
        dummy_atom = next(atom for atom in mol.GetAtoms() if atom.GetAtomicNum() == 0)
        neighbor = dummy_atom.GetNeighbors()[0]
        bond = mol.GetBondBetweenAtoms(dummy_atom.GetIdx(), neighbor.GetIdx())
        assert bond.GetBondType() == Chem.BondType.DOUBLE
