"""
任務中心相關資料表 Model(階段 2 切片 a)。

階段 2 第一個切片只先建兩張表:
  - projects ─ 專案(任務的容器,可選,沒指定就是 inbox)
  - tasks    ─ 任務本體

延後到階段 3 一併處理:
  - subtasks(子任務 / checklist)
  - task_assignments(指派 — 階段 2 暫時先把單一負責人塞在 tasks.assignee_id 簡化)
  - task_comments(留言)
  - task_activities(活動歷史)
  - task_attachments(附件)

設計理由:先把骨幹做出來能用,再慢慢加肉,避免一次堆太多功能反而沒一個能用。
"""

from datetime import date, datetime
from uuid import UUID, uuid4

from sqlalchemy import Date, DateTime, ForeignKey, Integer, String, Text, Uuid, func
from sqlalchemy.orm import Mapped, mapped_column, relationship

from app.database import Base
from app.models.user import TimestampMixin, User


class Project(Base, TimestampMixin):
    """專案 ─ 任務的容器。

    在 5-15 人小團隊裡,專案通常很少(可能 5-20 個),手動建立。
    每個任務「可以」屬於一個專案,也可以不屬於(就會出現在 Inbox)。
    """

    __tablename__ = "projects"

    id: Mapped[UUID] = mapped_column(Uuid(as_uuid=True), primary_key=True, default=uuid4)
    name: Mapped[str] = mapped_column(String(200), nullable=False)
    description: Mapped[str | None] = mapped_column(Text, nullable=True)

    # 顏色標籤,讓看板上的不同專案任務一眼可辨
    # 預設用品牌主色,使用者可以改成自己喜歡的顏色
    color: Mapped[str] = mapped_column(String(7), nullable=False, default="#1F4E79")

    # 專案負責人(通常是 owner,但也可以是某個 member)
    owner_id: Mapped[UUID] = mapped_column(
        Uuid(as_uuid=True),
        ForeignKey("users.id", ondelete="RESTRICT"),
        nullable=False,
        index=True,
    )

    # active / archived(歸檔的專案不會在預設視圖出現,但歷史保留)
    status: Mapped[str] = mapped_column(String(20), nullable=False, default="active")

    # 反向關聯:這個專案下的所有任務
    tasks: Mapped[list["Task"]] = relationship(
        back_populates="project",
        cascade="save-update, merge",  # 不串聯刪除,避免誤砍任務
        lazy="selectin",
    )

    # 多對一:擁有者
    owner: Mapped[User] = relationship(foreign_keys=[owner_id], lazy="joined")

    def __repr__(self) -> str:
        return f"<Project {self.name} status={self.status}>"


class Task(Base, TimestampMixin):
    """任務。

    狀態與優先順序設計:
      status:   todo / in_progress / review / done / cancelled
                看板的五個欄位,等同 Trello 的 List / Linear 的 Status。
      priority: low / medium / high / urgent

    指派(assignee_id)階段 2 用單一負責人,延後到階段 3 才開支援多人指派。
    """

    __tablename__ = "tasks"

    id: Mapped[UUID] = mapped_column(Uuid(as_uuid=True), primary_key=True, default=uuid4)

    # 可選的所屬專案(NULL = inbox)
    project_id: Mapped[UUID | None] = mapped_column(
        Uuid(as_uuid=True),
        ForeignKey("projects.id", ondelete="SET NULL"),
        nullable=True,
        index=True,
    )

    title: Mapped[str] = mapped_column(String(500), nullable=False)
    description: Mapped[str | None] = mapped_column(Text, nullable=True)

    status: Mapped[str] = mapped_column(String(20), nullable=False, default="todo", index=True)
    priority: Mapped[str] = mapped_column(String(10), nullable=False, default="medium")

    due_date: Mapped[date | None] = mapped_column(Date, nullable=True, index=True)

    # 階段 2 簡化:單一負責人
    # 階段 3 會擴展成獨立的 task_assignments 表(支援多人指派、誰指派的、何時指派)
    assignee_id: Mapped[UUID | None] = mapped_column(
        Uuid(as_uuid=True),
        ForeignKey("users.id", ondelete="SET NULL"),
        nullable=True,
        index=True,
    )

    # 建立者(作為 audit trail,即使後續被指派給別人也保留紀錄)
    created_by: Mapped[UUID] = mapped_column(
        Uuid(as_uuid=True),
        ForeignKey("users.id", ondelete="RESTRICT"),
        nullable=False,
    )

    # 看板上同一狀態欄內的排序(拖拉重排會更新這個值)
    # 使用 BIGINT 為了支援大量插入時不重排(用「中位數插值」演算法)
    order_index: Mapped[int] = mapped_column(Integer, nullable=False, default=0)

    # 完成時間(進入 done 狀態時記下,用於統計、燃盡圖等)
    completed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)

    # ---------- 關聯 ----------
    project: Mapped[Project | None] = relationship(back_populates="tasks", lazy="joined")
    assignee: Mapped[User | None] = relationship(foreign_keys=[assignee_id], lazy="joined")
    creator: Mapped[User] = relationship(foreign_keys=[created_by], lazy="joined")

    def __repr__(self) -> str:
        return f"<Task {self.title!r} status={self.status} priority={self.priority}>"
