# standard
import uuid
from dataclasses import asdict, dataclass, field
from datetime import datetime, timezone
from enum import Enum
from typing import Optional

# third party
# custom


def _now() -> str:
    return datetime.now(timezone.utc).isoformat()


def _uuid() -> str:
    return str(uuid.uuid4())


class TaskStatus(str, Enum):
    TODO = "todo"
    IN_PROGRESS = "in_progress"
    DONE = "done"


class TaskPriority(str, Enum):
    LOW = "low"
    MEDIUM = "medium"
    HIGH = "high"


@dataclass
class Task:
    title: str
    body: str = ""
    status: TaskStatus = TaskStatus.TODO
    priority: TaskPriority = TaskPriority.MEDIUM
    due_date: Optional[str] = None
    parent_id: Optional[str] = None
    completed_at: Optional[str] = None
    tags: list[str] = field(default_factory=list)
    id: str = field(default_factory=_uuid)
    created_at: str = field(default_factory=_now)
    updated_at: str = field(default_factory=_now)

    def to_dict(self) -> dict:
        d = asdict(self)
        d["status"] = self.status.value
        d["priority"] = self.priority.value
        return d

    def touch(self) -> None:
        self.updated_at = _now()

    def to_frontmatter_meta(self) -> dict:
        return {
            "id": self.id,
            "title": self.title,
            "status": self.status.value,
            "priority": self.priority.value,
            "due_date": self.due_date,
            "parent_id": self.parent_id,
            "completed_at": self.completed_at,
            "tags": self.tags,
            "created_at": self.created_at,
            "updated_at": self.updated_at,
        }

    @classmethod
    def from_dict(cls, meta: dict, body: str) -> "Task":
        return cls(
            id=meta.get("id", _uuid()),
            title=meta.get("title", ""),
            status=TaskStatus(meta.get("status", "todo")),
            priority=TaskPriority(meta.get("priority", "medium")),
            due_date=meta.get("due_date"),
            parent_id=meta.get("parent_id"),
            completed_at=meta.get("completed_at"),
            tags=meta.get("tags", []),
            created_at=meta.get("created_at", _now()),
            updated_at=meta.get("updated_at", _now()),
            body=body,
        )
