# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

from typing import Dict, List, Union, Optional
from datetime import datetime
from typing_extensions import Literal, TypeAlias

from ..._models import BaseModel

__all__ = [
    "DesignStopResponse",
    "Error",
    "Input",
    "InputTarget",
    "InputTargetEntity",
    "InputTargetEntityModification",
    "InputTargetEntityModificationCcdModificationResponse",
    "InputTargetEntityModificationSmilesModificationResponse",
    "InputMoleculeFilters",
    "InputMoleculeFiltersCustomFilter",
    "InputMoleculeFiltersCustomFilterLipinskiFilterResponse",
    "InputMoleculeFiltersCustomFilterRdkitDescriptorFilterResponse",
    "InputMoleculeFiltersCustomFilterRdkitDescriptorFilterResponseFractionCsp3",
    "InputMoleculeFiltersCustomFilterRdkitDescriptorFilterResponseMolLogp",
    "InputMoleculeFiltersCustomFilterRdkitDescriptorFilterResponseMolWt",
    "InputMoleculeFiltersCustomFilterRdkitDescriptorFilterResponseNumAromaticRings",
    "InputMoleculeFiltersCustomFilterRdkitDescriptorFilterResponseNumHAcceptors",
    "InputMoleculeFiltersCustomFilterRdkitDescriptorFilterResponseNumHDonors",
    "InputMoleculeFiltersCustomFilterRdkitDescriptorFilterResponseNumHeteroatoms",
    "InputMoleculeFiltersCustomFilterRdkitDescriptorFilterResponseNumRings",
    "InputMoleculeFiltersCustomFilterRdkitDescriptorFilterResponseNumRotatableBonds",
    "InputMoleculeFiltersCustomFilterRdkitDescriptorFilterResponseTpsa",
    "InputMoleculeFiltersCustomFilterSmartsCustomFilterResponse",
    "InputMoleculeFiltersCustomFilterSmartsCatalogFilterResponse",
    "InputMoleculeFiltersCustomFilterSmilesRegexFilterResponse",
    "Progress",
]


class Error(BaseModel):
    code: str
    """Machine-readable error code"""

    message: str
    """Human-readable error message"""

    details: Optional[object] = None
    """Additional error details"""


class InputTargetEntityModificationCcdModificationResponse(BaseModel):
    residue_index: int
    """0-based index of the residue to modify"""

    type: Literal["ccd"]

    value: str
    """CCD code from RCSB PDB (e.g.

    'MSE' for selenomethionine, 'SEP' for phosphoserine)
    """


class InputTargetEntityModificationSmilesModificationResponse(BaseModel):
    residue_index: int
    """0-based index of the residue to modify"""

    type: Literal["smiles"]

    value: str
    """SMILES string for the modification"""


InputTargetEntityModification: TypeAlias = Union[
    InputTargetEntityModificationCcdModificationResponse, InputTargetEntityModificationSmilesModificationResponse
]


class InputTargetEntity(BaseModel):
    chain_ids: List[str]
    """Chain IDs for this entity"""

    modifications: List[InputTargetEntityModification]
    """Post-translational modifications"""

    type: Literal["protein"]

    value: str
    """Amino acid sequence (one-letter codes)"""

    cyclic: Optional[bool] = None
    """Whether the sequence is cyclic"""


class InputTarget(BaseModel):
    """Target protein with binding pocket for small molecule design or screening"""

    entities: List[InputTargetEntity]
    """Protein entities defining the target structure.

    Each entity represents a protein chain.
    """

    pocket_residues: Optional[Dict[str, List[int]]] = None
    """Binding pocket residues, keyed by chain ID.

    Each key is a chain ID (e.g. "A") and the value is an array of 0-indexed residue
    indices that define the binding pocket on that chain. When provided, these
    residues guide pocket extraction. When omitted, the model auto-detects the
    pocket.
    """

    reference_ligands: Optional[List[str]] = None
    """
    Reference ligands as SMILES strings that help the model identify the binding
    pocket. When omitted, a set of drug-like default ligands is used for pocket
    detection.
    """


class InputMoleculeFiltersCustomFilterLipinskiFilterResponse(BaseModel):
    """Lipinski's Rule of Five filter.

    Rejects molecules that violate drug-likeness criteria based on molecular weight, LogP, hydrogen bond donors, and hydrogen bond acceptors.
    """

    max_hba: float
    """Maximum number of hydrogen bond acceptors. Lipinski threshold: 10"""

    max_hbd: float
    """Maximum number of hydrogen bond donors. Lipinski threshold: 5"""

    max_logp: float
    """Maximum LogP. Lipinski threshold: 5"""

    max_mw: float
    """Maximum molecular weight (Da). Lipinski threshold: 500"""

    type: Literal["lipinski_filter"]

    allow_single_violation: Optional[bool] = None
    """If true, one rule violation is allowed (classic Rule of Five).

    Defaults to false (all rules must pass).
    """


class InputMoleculeFiltersCustomFilterRdkitDescriptorFilterResponseFractionCsp3(BaseModel):
    """Min/max range constraint for an RDKit molecular descriptor"""

    max: Optional[float] = None
    """Maximum allowed value (inclusive)"""

    min: Optional[float] = None
    """Minimum allowed value (inclusive)"""


class InputMoleculeFiltersCustomFilterRdkitDescriptorFilterResponseMolLogp(BaseModel):
    """Min/max range constraint for an RDKit molecular descriptor"""

    max: Optional[float] = None
    """Maximum allowed value (inclusive)"""

    min: Optional[float] = None
    """Minimum allowed value (inclusive)"""


class InputMoleculeFiltersCustomFilterRdkitDescriptorFilterResponseMolWt(BaseModel):
    """Min/max range constraint for an RDKit molecular descriptor"""

    max: Optional[float] = None
    """Maximum allowed value (inclusive)"""

    min: Optional[float] = None
    """Minimum allowed value (inclusive)"""


class InputMoleculeFiltersCustomFilterRdkitDescriptorFilterResponseNumAromaticRings(BaseModel):
    """Min/max range constraint for an RDKit molecular descriptor"""

    max: Optional[float] = None
    """Maximum allowed value (inclusive)"""

    min: Optional[float] = None
    """Minimum allowed value (inclusive)"""


class InputMoleculeFiltersCustomFilterRdkitDescriptorFilterResponseNumHAcceptors(BaseModel):
    """Min/max range constraint for an RDKit molecular descriptor"""

    max: Optional[float] = None
    """Maximum allowed value (inclusive)"""

    min: Optional[float] = None
    """Minimum allowed value (inclusive)"""


class InputMoleculeFiltersCustomFilterRdkitDescriptorFilterResponseNumHDonors(BaseModel):
    """Min/max range constraint for an RDKit molecular descriptor"""

    max: Optional[float] = None
    """Maximum allowed value (inclusive)"""

    min: Optional[float] = None
    """Minimum allowed value (inclusive)"""


class InputMoleculeFiltersCustomFilterRdkitDescriptorFilterResponseNumHeteroatoms(BaseModel):
    """Min/max range constraint for an RDKit molecular descriptor"""

    max: Optional[float] = None
    """Maximum allowed value (inclusive)"""

    min: Optional[float] = None
    """Minimum allowed value (inclusive)"""


class InputMoleculeFiltersCustomFilterRdkitDescriptorFilterResponseNumRings(BaseModel):
    """Min/max range constraint for an RDKit molecular descriptor"""

    max: Optional[float] = None
    """Maximum allowed value (inclusive)"""

    min: Optional[float] = None
    """Minimum allowed value (inclusive)"""


class InputMoleculeFiltersCustomFilterRdkitDescriptorFilterResponseNumRotatableBonds(BaseModel):
    """Min/max range constraint for an RDKit molecular descriptor"""

    max: Optional[float] = None
    """Maximum allowed value (inclusive)"""

    min: Optional[float] = None
    """Minimum allowed value (inclusive)"""


class InputMoleculeFiltersCustomFilterRdkitDescriptorFilterResponseTpsa(BaseModel):
    """Min/max range constraint for an RDKit molecular descriptor"""

    max: Optional[float] = None
    """Maximum allowed value (inclusive)"""

    min: Optional[float] = None
    """Minimum allowed value (inclusive)"""


class InputMoleculeFiltersCustomFilterRdkitDescriptorFilterResponse(BaseModel):
    """Filter molecules by RDKit molecular descriptors.

    Each descriptor is constrained to a min/max range. Only descriptors you provide are checked — omitted descriptors are unconstrained.
    """

    type: Literal["rdkit_descriptor_filter"]

    fraction_csp3: Optional[InputMoleculeFiltersCustomFilterRdkitDescriptorFilterResponseFractionCsp3] = None
    """Min/max range constraint for an RDKit molecular descriptor"""

    mol_logp: Optional[InputMoleculeFiltersCustomFilterRdkitDescriptorFilterResponseMolLogp] = None
    """Min/max range constraint for an RDKit molecular descriptor"""

    mol_wt: Optional[InputMoleculeFiltersCustomFilterRdkitDescriptorFilterResponseMolWt] = None
    """Min/max range constraint for an RDKit molecular descriptor"""

    num_aromatic_rings: Optional[InputMoleculeFiltersCustomFilterRdkitDescriptorFilterResponseNumAromaticRings] = None
    """Min/max range constraint for an RDKit molecular descriptor"""

    num_h_acceptors: Optional[InputMoleculeFiltersCustomFilterRdkitDescriptorFilterResponseNumHAcceptors] = None
    """Min/max range constraint for an RDKit molecular descriptor"""

    num_h_donors: Optional[InputMoleculeFiltersCustomFilterRdkitDescriptorFilterResponseNumHDonors] = None
    """Min/max range constraint for an RDKit molecular descriptor"""

    num_heteroatoms: Optional[InputMoleculeFiltersCustomFilterRdkitDescriptorFilterResponseNumHeteroatoms] = None
    """Min/max range constraint for an RDKit molecular descriptor"""

    num_rings: Optional[InputMoleculeFiltersCustomFilterRdkitDescriptorFilterResponseNumRings] = None
    """Min/max range constraint for an RDKit molecular descriptor"""

    num_rotatable_bonds: Optional[InputMoleculeFiltersCustomFilterRdkitDescriptorFilterResponseNumRotatableBonds] = None
    """Min/max range constraint for an RDKit molecular descriptor"""

    tpsa: Optional[InputMoleculeFiltersCustomFilterRdkitDescriptorFilterResponseTpsa] = None
    """Min/max range constraint for an RDKit molecular descriptor"""


class InputMoleculeFiltersCustomFilterSmartsCustomFilterResponse(BaseModel):
    """Filter molecules by custom SMARTS patterns.

    Molecules matching any pattern are rejected.
    """

    patterns: List[str]
    """SMARTS patterns. Molecules matching any pattern are rejected."""

    type: Literal["smarts_custom_filter"]


class InputMoleculeFiltersCustomFilterSmartsCatalogFilterResponse(BaseModel):
    """Filter molecules using a predefined SMARTS catalog of structural alerts."""

    catalog: Literal[
        "PAINS",
        "PAINS_A",
        "PAINS_B",
        "PAINS_C",
        "BRENK",
        "CHEMBL",
        "CHEMBL_BMS",
        "CHEMBL_Dundee",
        "CHEMBL_Glaxo",
        "CHEMBL_Inpharmatica",
        "CHEMBL_LINT",
        "CHEMBL_MLSMR",
        "CHEMBL_SureChEMBL",
        "NIH",
    ]
    """Predefined SMARTS catalog to apply.

    PAINS, BRENK, ChEMBL, and NIH catalogs reject known problematic substructures.
    """

    type: Literal["smarts_catalog_filter"]


class InputMoleculeFiltersCustomFilterSmilesRegexFilterResponse(BaseModel):
    """Filter molecules by regex patterns on their SMILES representation."""

    patterns: List[str]
    """Regex patterns applied to SMILES strings.

    Molecules matching any pattern are rejected.
    """

    type: Literal["smiles_regex_filter"]


InputMoleculeFiltersCustomFilter: TypeAlias = Union[
    InputMoleculeFiltersCustomFilterLipinskiFilterResponse,
    InputMoleculeFiltersCustomFilterRdkitDescriptorFilterResponse,
    InputMoleculeFiltersCustomFilterSmartsCustomFilterResponse,
    InputMoleculeFiltersCustomFilterSmartsCatalogFilterResponse,
    InputMoleculeFiltersCustomFilterSmilesRegexFilterResponse,
]


class InputMoleculeFilters(BaseModel):
    """Molecule filtering configuration.

    Controls both Boltz built-in SMARTS filtering and custom filters.
    """

    boltz_smarts_catalog_filter_level: Optional[Literal["recommended", "extra", "aggressive", "disabled"]] = None
    """
    Controls the stringency of Boltz's built-in SMARTS structural alert filtering,
    which removes molecules matching known problematic substructures. 'recommended'
    (default): applies a curated set of alerts balancing safety and hit rate.
    'extra': adds additional alerts beyond the recommended set for stricter
    filtering. 'aggressive': applies the most comprehensive alert set — may reject
    viable molecules. 'disabled': turns off Boltz SMARTS filtering entirely; only
    custom_filters will be applied.
    """

    custom_filters: Optional[List[InputMoleculeFiltersCustomFilter]] = None
    """Custom filters to apply. Molecules must pass all filters (AND logic)."""


class Input(BaseModel):
    num_molecules: int
    """Number of molecules to generate"""

    target: InputTarget
    """Target protein with binding pocket for small molecule design or screening"""

    chemical_space: Optional[Literal["enamine_real"]] = None
    """Chemical space to constrain generated molecules.

    Currently only 'enamine_real' (Enamine REAL chemical space) is supported.
    Additional options may be added in the future.
    """

    idempotency_key: Optional[str] = None
    """Client-provided key to prevent duplicate submissions on retries"""

    molecule_filters: Optional[InputMoleculeFilters] = None
    """Molecule filtering configuration.

    Controls both Boltz built-in SMARTS filtering and custom filters.
    """

    workspace_id: Optional[str] = None
    """Target workspace ID (admin keys only; ignored for workspace keys)"""


class Progress(BaseModel):
    num_molecules_generated: int
    """Number of molecules generated so far"""

    total_molecules_to_generate: int
    """Total number of molecules requested"""

    latest_result_id: Optional[str] = None
    """ID of the most recently generated result"""


class DesignStopResponse(BaseModel):
    """A small molecule design engine run that generates novel molecules"""

    id: str
    """Unique SmDesignRun identifier"""

    completed_at: Optional[datetime] = None

    created_at: datetime

    data_deleted_at: Optional[datetime] = None
    """When the input, output, and result data was permanently deleted.

    Null if data has not been deleted.
    """

    engine: Literal["boltz-sm-design"]
    """Engine used for small molecule design"""

    engine_version: str
    """Engine version used for small molecule design"""

    error: Optional[Error] = None

    input: Input

    livemode: bool
    """Whether this resource was created with a live API key."""

    progress: Optional[Progress] = None

    started_at: Optional[datetime] = None

    status: Literal["pending", "running", "succeeded", "failed", "stopped"]

    stopped_at: Optional[datetime] = None

    workspace_id: str
    """Workspace ID"""

    idempotency_key: Optional[str] = None
    """Client-provided idempotency key"""
