from typing import Self

from pydantic import model_validator

from .base import Base, LowercaseStrEnum, UniqueList
from .message import Message
from .molecule import Molecule
from .settings import Settings
from .status import Status
from .task import Task
from .types import UUID


class StJamesVersion(LowercaseStrEnum):
    """
    Flag for which version of stjames this calculation was saved in.
    This will become meaningful later, when we have (probably) multiple versions.
    """

    V0 = "09072023"


class Calculation(Base):
    """
    Computational chemistry calculation.

    :param molecules: molecules generated by the calculation
    :param tasks: tasks to perform (energy, optimize, etc.)
    :param settings: computational settings
    :param status: execution status
    :param name: name for calculation
    :param elapsed: wall time (s)
    :param logfile: calculation log output
    :param messages: user-facing messages
    :param engine: deprecated, use settings.engine
    :param uuids: UUIDs of calculations in database
    :param json_format: stjames version identifier
    """

    molecules: list[Molecule]

    tasks: UniqueList[Task] = []
    settings: Settings = Settings()

    status: Status = Status.QUEUED

    name: str | None = None
    elapsed: float | None = None
    logfile: str | None = None
    messages: list[Message] = []

    # DEPRECATED - moving into settings
    engine: str | None = "peregrine"

    uuids: list[UUID | None] | None = None

    # not to be changed by end users, diff. versions will have diff. defaults
    json_format: str = StJamesVersion.V0

    @model_validator(mode="after")
    def populate_tasks(self) -> Self:
        """Set the tasks from the settings, so that we don't have to migrate old entries."""
        if len(self.tasks) == 0:
            self.tasks = self.settings.tasks
        return self
