from dataclasses import dataclass
from datetime import datetime, timezone
from enum import Enum
from typing import Any, Optional
from uuid import UUID, uuid4


class SubTaskStatus(str, Enum):
    WAITING = "waiting"
    IN_PROGRESS = "in progress"
    COMPLETE = "complete"
    FAILED = "failed"


@dataclass
class SubTask:
    id: UUID
    task_id: UUID
    status: SubTaskStatus = SubTaskStatus.WAITING
    inputs: Optional[dict[str, Any]] = None
    outputs: Optional[dict[str, Any]] = None
    cloud_logs_url: Optional[str] = None
    job_started: Optional[datetime] = None
    job_completed: Optional[datetime] = None

    @classmethod
    def create(
        cls, *, task_id: UUID, inputs: Optional[dict[str, Any]] = None
    ) -> "SubTask":
        return cls(
            id=uuid4(),
            task_id=task_id,
            status=SubTaskStatus.WAITING,
            inputs=inputs,
        )

    def start(self, cloud_logs_url: Optional[str] = None) -> None:
        if self.status not in (SubTaskStatus.WAITING, SubTaskStatus.IN_PROGRESS):
            raise ValueError(f"cannot start subtask in status {self.status}")
        if self.job_started is None:
            self.job_started = datetime.now(timezone.utc)
        self.status = SubTaskStatus.IN_PROGRESS
        if cloud_logs_url is not None:
            self.cloud_logs_url = cloud_logs_url

    def complete(self, result: Any = None) -> None:
        self.status = SubTaskStatus.COMPLETE
        self.job_completed = datetime.now(timezone.utc)
        if result is not None:
            self.outputs = {"result": result}

    def fail(self, error: BaseException) -> None:
        self.status = SubTaskStatus.FAILED
        self.job_completed = datetime.now(timezone.utc)
        self.outputs = {"error": str(error)}
