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

from domain.tasks.subtasks import SubTaskStatus


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


class Source(str, Enum):
    PORTFOLIO = "portfolio_id"
    HUBSPOT_DEAL = "hubspot_deal_id"


@dataclass
class Task:
    id: UUID
    task_source: str
    status: TaskStatus = TaskStatus.WAITING
    service: Optional[str] = None
    source: Optional[Source] = None
    source_id: Optional[str] = None
    job_started: Optional[datetime] = None
    job_completed: Optional[datetime] = None

    @classmethod
    def create(
        cls,
        *,
        task_source: str,
        service: Optional[str] = None,
        source: Optional[Source] = None,
        source_id: Optional[str] = None,
    ) -> "Task":
        if not task_source.strip():
            raise ValueError("task_source must be non-empty")
        return cls(
            id=uuid4(),
            task_source=task_source,
            service=service,
            source=source,
            source_id=source_id,
            status=TaskStatus.WAITING,
            job_started=datetime.now(timezone.utc),
        )

    def start(self) -> None:
        if self.status not in (TaskStatus.WAITING, TaskStatus.IN_PROGRESS):
            raise ValueError(f"cannot start task in status {self.status}")
        if self.job_started is None:
            self.job_started = datetime.now(timezone.utc)
        self.status = TaskStatus.IN_PROGRESS

    def complete(self) -> None:
        self.status = TaskStatus.COMPLETE
        self.job_completed = datetime.now(timezone.utc)

    def fail(self) -> None:
        self.status = TaskStatus.FAILED
        self.job_completed = datetime.now(timezone.utc)

    def recalculate_from_subtasks(self, statuses: list[SubTaskStatus]) -> None:
        """Recompute Task.status from its SubTasks' statuses.

        Rule (preserved from legacy _update_task_progress):
          - any FAILED       → FAILED
          - all COMPLETE     → COMPLETE
          - any IN_PROGRESS  → IN_PROGRESS
          - otherwise        → WAITING

        Empty list is a no-op (newly-created task with no subtasks).
        """
        if not statuses:
            return
        now = datetime.now(timezone.utc)
        if SubTaskStatus.FAILED in statuses:
            self.status = TaskStatus.FAILED
            self.job_completed = now
        elif all(s is SubTaskStatus.COMPLETE for s in statuses):
            self.status = TaskStatus.COMPLETE
            self.job_completed = now
        elif SubTaskStatus.IN_PROGRESS in statuses:
            self.status = TaskStatus.IN_PROGRESS
            self.job_completed = None
        else:
            self.status = TaskStatus.WAITING
            self.job_completed = None
