import enum import uuid from datetime import date from sqlalchemy import Boolean, Date, Enum, ForeignKey, String, Text from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.orm import Mapped, mapped_column, relationship from api.models.base import Base, TimestampMixin, new_uuid class TaskStatus(str, enum.Enum): todo = "todo" in_progress = "in_progress" blocked = "blocked" done = "done" cancelled = "cancelled" class TaskPriority(str, enum.Enum): low = "low" medium = "medium" high = "high" critical = "critical" class Task(Base, TimestampMixin): __tablename__ = "tasks" id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), primary_key=True, default=new_uuid ) workstream_id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("workstreams.id", ondelete="RESTRICT"), nullable=False, index=True ) title: Mapped[str] = mapped_column(String(255), nullable=False) description: Mapped[str | None] = mapped_column(Text, nullable=True) status: Mapped[TaskStatus] = mapped_column( Enum(TaskStatus), nullable=False, default=TaskStatus.todo ) priority: Mapped[TaskPriority] = mapped_column( Enum(TaskPriority), nullable=False, default=TaskPriority.medium ) assignee: Mapped[str | None] = mapped_column(String(100), nullable=True) due_date: Mapped[date | None] = mapped_column(Date, nullable=True) blocking_reason: Mapped[str | None] = mapped_column(Text, nullable=True) needs_human: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False, index=True) intervention_note: Mapped[str | None] = mapped_column(Text, nullable=True) parent_task_id: Mapped[uuid.UUID | None] = mapped_column( UUID(as_uuid=True), ForeignKey("tasks.id", ondelete="SET NULL"), nullable=True ) workstream: Mapped["Workstream"] = relationship("Workstream", back_populates="tasks") # noqa: F821 subtasks: Mapped[list["Task"]] = relationship( "Task", foreign_keys=[parent_task_id], lazy="selectin" ) progress_events: Mapped[list["ProgressEvent"]] = relationship( # noqa: F821 "ProgressEvent", back_populates="task", lazy="selectin" )