# backend/app/models.py
# 주의: `from __future__ import annotations` 를 쓰지 않는다 —
# SQLAlchemy 2.x 가 Relationship 의 list["Project"] 문자열 주석을 해석하지 못해
# 매퍼 초기화에 실패한다(ForwardRef 로 평가되도록 둔다).
from datetime import UTC, date, datetime
from enum import Enum
from typing import Optional

from sqlmodel import Field, Relationship, SQLModel


def now() -> datetime:
    return datetime.now(UTC)


# ---------- enums (값은 CONTRACT 고정) ----------
class TaskStatus(str, Enum):
    todo = "todo"
    doing = "doing"
    waiting = "waiting"
    review = "review"
    done = "done"


class Prio(str, Enum):
    high = "높음"
    normal = "보통"
    low = "낮음"


class InboxKind(str, Enum):
    text = "text"
    voice = "voice"
    image = "image"


class InboxStatus(str, Enum):
    new = "new"
    classified = "classified"
    confirmed = "confirmed"
    dismissed = "dismissed"


class ClsType(str, Enum):
    task = "task"
    event = "event"
    idea = "idea"


class Sphere(str, Enum):
    work = "work"
    life = "life"


# ---------- core ----------
class Person(SQLModel, table=True):
    __tablename__ = "person"
    id: str = Field(primary_key=True)  # 예: "jiwoo"
    name: str
    initial: str
    color: str  # 예: "var(--blue)" / "oklch(0.66 0.13 200)"
    is_me: bool = False


class Folder(SQLModel, table=True):
    __tablename__ = "folder"
    id: str = Field(primary_key=True)  # "work" / "life"
    name: str  # "업무" / "개인"
    tone: str = "ink"  # tone 집합: blue|violet|coral|green|amber|ink|faint
    icon: str = "folder"  # "folder" / "heart"
    sort_order: int = 0
    is_system: bool = True

    projects: list["Project"] = Relationship(back_populates="folder")


class Project(SQLModel, table=True):
    __tablename__ = "project"
    id: str = Field(primary_key=True)  # "biz", "biz-okr", ...
    folder_id: str = Field(foreign_key="folder.id")
    parent_id: Optional[str] = Field(default=None, foreign_key="project.id")  # 무한 중첩
    name: str
    tone: str = "ink"
    sort_order: int = 0
    pinned: bool = False  # 즐겨찾기

    folder: Optional[Folder] = Relationship(back_populates="projects")
    parent: Optional["Project"] = Relationship(
        back_populates="children",
        sa_relationship_kwargs={"remote_side": "Project.id"},
    )
    children: list["Project"] = Relationship(back_populates="parent")
    tasks: list["Task"] = Relationship(back_populates="project")


class Task(SQLModel, table=True):
    __tablename__ = "task"
    id: str = Field(primary_key=True)  # "k1", "kx3", ...
    project_id: str = Field(foreign_key="project.id")
    parent_id: Optional[str] = Field(default=None, foreign_key="task.id")  # 무한 중첩 하위작업
    title: str
    status: TaskStatus = TaskStatus.todo
    assignee_id: Optional[str] = Field(default=None, foreign_key="person.id")
    due: Optional[date] = None  # 시드는 "06-08" → 2026-06-08 로 적재
    prio: Prio = Prio.normal
    notes: str = ""  # HTML 허용
    est: str = ""
    delegated: bool = False
    sort_order: int = 0
    created_at: datetime = Field(default_factory=now)
    updated_at: datetime = Field(default_factory=now)

    project: Optional[Project] = Relationship(back_populates="tasks")
    parent: Optional["Task"] = Relationship(
        back_populates="children",
        sa_relationship_kwargs={"remote_side": "Task.id"},
    )
    children: list["Task"] = Relationship(back_populates="parent")
    comments: list["TaskComment"] = Relationship(back_populates="task")
    assignee: Optional[Person] = Relationship()


class TaskComment(SQLModel, table=True):
    __tablename__ = "task_comment"
    id: str = Field(primary_key=True)  # TEXT PK 예: "c1"
    task_id: str = Field(foreign_key="task.id")
    person_id: str = Field(foreign_key="person.id")
    text: str
    created_at: datetime = Field(default_factory=now)

    task: Optional[Task] = Relationship(back_populates="comments")
    person: Optional[Person] = Relationship()


# ---------- inbox (연합의 핵심) ----------
class InboxItem(SQLModel, table=True):
    __tablename__ = "inbox_item"
    id: str = Field(primary_key=True)  # "s1", ...
    kind: InboxKind = InboxKind.text
    raw: str
    status: InboxStatus = InboxStatus.new
    created_at: datetime = Field(default_factory=now)
    materialized_task_id: Optional[str] = Field(default=None, foreign_key="task.id")

    classifications: list["InboxClassification"] = Relationship(back_populates="item")


class InboxClassification(SQLModel, table=True):
    __tablename__ = "inbox_classification"
    id: str = Field(primary_key=True)  # TEXT PK 예: "cls1"
    inbox_item_id: str = Field(foreign_key="inbox_item.id")  # 1:1 최신
    type: ClsType
    sphere: Sphere
    project_id: Optional[str] = Field(default=None, foreign_key="project.id")
    proj_label: str = ""  # 예: "개인 › 여행 — 한국"
    tone: str = "ink"
    due_text: str = ""  # 예: "출발 전 · ~6/14"
    when_text: str = ""  # 예: "오늘 21:00 빈 시간 추천"
    extra: str = ""  # 예: "가격 추적 알림 켜둠"
    reason: str = ""  # 사람이 읽는 한국어 설명
    confidence: float = 0.0
    model: str = ""  # 사용된 provider/model 표기
    created_at: datetime = Field(default_factory=now)

    item: Optional[InboxItem] = Relationship(back_populates="classifications")


# ---------- 대시보드 읽기전용 시드 ----------
class Event(SQLModel, table=True):
    __tablename__ = "event"
    id: str = Field(primary_key=True)  # TEXT PK 예: "e1"
    time: str
    title: str
    tag: str = ""
    dur: str = ""
    tone: str = "ink"  # tone 키 값('blue' 등). 'var(--blue)' 저장 금지
    soon: bool = False
    sort_order: int = 0


class Approval(SQLModel, table=True):
    __tablename__ = "approval"
    id: str = Field(primary_key=True)  # "a1", ...
    icon: str
    tone: str
    risk: str  # "low" | "high"
    time: str
    title: str
    detail: str = ""
    cta: str = ""
    alt: str = ""
    undo_label: str = ""
    sort_order: int = 0


class Goal(SQLModel, table=True):
    __tablename__ = "goal"
    id: str = Field(primary_key=True)  # TEXT PK 예: "g1"
    title: str
    pct: int
    sub: str = ""
    tone: str = "blue"  # tone 키 값('blue' 등). 'var(--blue)' 저장 금지
    sort_order: int = 0


class Briefing(SQLModel, table=True):
    """단일 row(id=1). 아침 브리핑 + 날씨/출근/수면 + saved_today/today_routed."""

    __tablename__ = "briefing"
    id: Optional[int] = Field(default=None, primary_key=True)  # 단일 row id=1
    today: str = ""  # 히어로 날짜 라벨 (예: "6월 7일 일요일")
    weather_temp: int = 0  # 현재 기온 (예: 24)
    weather_cond: str = ""  # "맑음 · 한낮 28°" — "한낮 28°"는 일 최고기온
    weather_icon: str = "cloudSun"  # 'cloudSun' 저장 → 표시 시 'sun' 으로 매핑
    commute: str = ""
    sleep: str = ""
    note: str = ""  # HTML 허용
    saved_today: str = ""  # "47분"
    today_routed: int = 0  # 7
