from __future__ import annotations

from dataclasses import asdict, dataclass, field
from typing import Literal


@dataclass(frozen=True)
class RingNumberingResult:
    ring_size: int
    ring_atoms: list[int]
    ordered_atoms: list[int]
    carbonyl_carbon_idx: int
    ester_oxygen_idx: int
    atom_to_position: dict[int, int]
    position_to_atom: dict[int, int]

    def to_dict(self) -> dict:
        return asdict(self)


@dataclass(frozen=True)
class SideChainFragment:
    parent_id: str
    fragment_id: str
    cleavage_position: int
    attachment_atom_idx: int
    fragment_smiles_labeled: str
    fragment_smiles_plain: str
    atom_count: int
    molecular_weight: float

    def to_dict(self) -> dict:
        return asdict(self)


@dataclass(frozen=True)
class FragmentationResult:
    parent_id: str
    parent_smiles: str
    ring_size: int
    numbering: RingNumberingResult
    fragments: list[SideChainFragment] = field(default_factory=list)
    warnings: list[str] = field(default_factory=list)

    def to_dict(self) -> dict:
        return {
            "parent_id": self.parent_id,
            "parent_smiles": self.parent_smiles,
            "ring_size": self.ring_size,
            "numbering": self.numbering.to_dict(),
            "fragments": [fragment.to_dict() for fragment in self.fragments],
            "warnings": list(self.warnings),
        }


@dataclass(frozen=True)
class MacrocycleClassificationResult:
    smiles: str
    classification: Literal[
        "standard_macrolactone",
        "non_standard_macrocycle",
        "not_macrolactone",
    ]
    ring_size: int | None
    primary_reason_code: str | None
    primary_reason_message: str | None
    all_reason_codes: list[str] = field(default_factory=list)
    all_reason_messages: list[str] = field(default_factory=list)
    candidate_ring_sizes: list[int] = field(default_factory=list)

    def to_dict(self) -> dict:
        return asdict(self)
