# backend/app/schemas.py
from __future__ import annotations

from datetime import date, datetime
from typing import Optional

from pydantic import BaseModel

from .models import ClsType, InboxKind, InboxStatus, Prio, Sphere, TaskStatus


# ---------- people ----------
class PersonOut(BaseModel):
    id: str
    name: str
    initial: str
    color: str
    is_me: bool


# ---------- tree ----------
class ProjectNode(BaseModel):
    id: str
    folder_id: str
    parent_id: Optional[str] = None
    name: str
    tone: str
    sort_order: int
    pinned: bool
    task_count: int = 0  # 자신+하위 프로젝트의 작업 수 합
    children: list[ProjectNode] = []


class FolderOut(BaseModel):
    id: str
    name: str
    tone: str
    icon: str
    sort_order: int
    is_system: bool
    projects: list[ProjectNode] = []  # 최상위 프로젝트(중첩 children 포함)


class FolderCreate(BaseModel):
    name: str
    tone: Optional[str] = "ink"
    icon: Optional[str] = "folder"


class FolderPatch(BaseModel):
    name: Optional[str] = None
    tone: Optional[str] = None
    icon: Optional[str] = None
    sort_order: Optional[int] = None


class ProjectCreate(BaseModel):
    folder_id: str
    parent_id: Optional[str] = None
    name: str
    tone: Optional[str] = "ink"


class ProjectPatch(BaseModel):
    name: Optional[str] = None
    tone: Optional[str] = None
    parent_id: Optional[str] = None
    sort_order: Optional[int] = None


# ---------- tasks ----------
class CommentOut(BaseModel):
    id: str
    task_id: str
    person_id: str
    text: str
    created_at: datetime


class TaskNode(BaseModel):
    id: str
    project_id: str
    parent_id: Optional[str] = None
    title: str
    status: TaskStatus
    assignee_id: Optional[str] = None
    due: Optional[date] = None
    prio: Prio
    notes: str
    est: str
    delegated: bool
    sort_order: int
    created_at: datetime
    updated_at: datetime
    comments: list[CommentOut] = []
    children: list[TaskNode] = []


class TaskCreate(BaseModel):
    title: str
    project_id: str
    parent_id: Optional[str] = None
    status: Optional[TaskStatus] = TaskStatus.todo
    assignee_id: Optional[str] = None
    due: Optional[date] = None
    prio: Optional[Prio] = Prio.normal
    notes: Optional[str] = ""
    est: Optional[str] = ""


class TaskPatch(BaseModel):
    title: Optional[str] = None
    project_id: Optional[str] = None
    parent_id: Optional[str] = None
    status: Optional[TaskStatus] = None
    assignee_id: Optional[str] = None
    due: Optional[date] = None
    prio: Optional[Prio] = None
    notes: Optional[str] = None
    est: Optional[str] = None
    delegated: Optional[bool] = None
    sort_order: Optional[int] = None


class CommentCreate(BaseModel):
    person_id: str
    text: str


# ---------- scaffold ----------
class ScaffoldItem(BaseModel):
    title: str
    est: str = ""


class ScaffoldOut(BaseModel):
    kind: str  # "연구 · 논문 작성" 등
    icon: str  # "brain"|"branch"|"file"|"list"
    items: list[ScaffoldItem]
    created: bool = False  # True면 실제 생성됨, False면 미리보기
    created_task_ids: list[str] = []


class ScaffoldRequest(BaseModel):
    create: bool = False  # True면 하위작업 실제 생성, False면 미리보기
    use_llm: bool = False  # LLM 보강 사용 여부


# ---------- risks ----------
class RiskOut(BaseModel):
    kind: str  # "지연 위험" | "업무 쏠림" | "의존성"
    icon: str  # "clock" | "scale" | "link"
    tone: str  # "coral" | "amber" | "violet"
    task_id: Optional[str] = None  # 관련 task id (cta 대상)
    text: str  # 한국어. 강조어를 ** ** 마크다운으로 감싼다
    cta: Optional[str] = None  # "작업 열기" | "후속 작업 보기"


# ---------- inbox ----------
class ClassificationOut(BaseModel):
    id: Optional[str] = None
    inbox_item_id: str
    type: ClsType
    sphere: Sphere
    project_id: Optional[str] = None
    proj_label: str
    tone: str
    due_text: str
    when_text: str
    extra: str
    reason: str
    confidence: float
    model: str
    created_at: Optional[datetime] = None


class InboxItemOut(BaseModel):
    id: str
    kind: InboxKind
    raw: str
    status: InboxStatus
    created_at: datetime
    materialized_task_id: Optional[str] = None
    classification: Optional[ClassificationOut] = None  # 최신 1건


class CaptureRequest(BaseModel):
    kind: InboxKind = InboxKind.text
    raw: str


class CaptureResponse(BaseModel):
    item: InboxItemOut
    classification: ClassificationOut


class ReclassifyRequest(BaseModel):
    type: Optional[ClsType] = None  # 사용자가 타입 강제 가능


class ConfirmResponse(BaseModel):
    item: InboxItemOut
    task: Optional[TaskNode] = None  # type=task 면 생성된 작업


# ---------- llm ----------
class LLMHealth(BaseModel):
    reachable: bool
    provider: str  # "ollama" | "heuristic"
    model: str
    host: Optional[str] = None
    detail: str = ""


# ---------- dashboard ----------
class UserOut(BaseModel):
    name: str  # 예: "지우"
    initial: str  # 예: "지"


class WeatherOut(BaseModel):
    temp: int  # 현재 기온 (예: 24)
    cond: str  # "맑음 · 한낮 28°"
    icon: str  # 'cloudSun' 저장 → 표시용 'sun' 으로 매핑


class BriefingOut(BaseModel):
    today: str  # 히어로 날짜 라벨 (예: "6월 7일 일요일")
    weather: WeatherOut
    commute: str
    sleep: str
    note: str  # HTML 허용


class EventOut(BaseModel):
    id: str
    time: str
    title: str
    tag: str
    dur: str
    tone: str
    soon: bool


class ApprovalSummaryOut(BaseModel):
    id: str
    icon: str
    tone: str
    title: str
    time: str
    # risk=="high" 만 포함, 최대 3건. detail/cta/alt/undo_label 미포함.


class GoalOut(BaseModel):
    id: str
    title: str
    pct: int
    sub: str
    tone: str  # tone=키('blue' 등)


class InboxRecentOut(BaseModel):
    id: str
    kind: str
    raw: str
    type: str
    proj_label: str
    tone: str
    # 평탄화 형태: 최신 classification 에서 type/proj_label/tone 을 끌어와 채운다.


class TaskSummaryItem(BaseModel):
    id: str
    title: str
    prio: str
    project: str


class TaskSummaryOut(BaseModel):
    open_count: int  # 미완료 작업 수
    items: list[TaskSummaryItem]


class BadgesOut(BaseModel):
    appr: int  # 결재함 대기(=high risk 건수)
    task: int  # 미완료 작업 수(상단 작업 배지)
    noti: int  # 알림 배지 (시드 상수 6)


class DashboardOut(BaseModel):
    user: UserOut
    briefing: BriefingOut
    saved_today: str  # "47분"
    today_routed: int  # 7
    schedule: list[EventOut]
    task_summary: TaskSummaryOut
    goals: list[GoalOut]
    approvals_summary: list[ApprovalSummaryOut]  # high-risk 만, 최대 3건
    inbox_recent: list[InboxRecentOut]  # 최근 3 (평탄화 형태)
    badges: BadgesOut


# 재귀 모델 전방참조 해소
ProjectNode.model_rebuild()
TaskNode.model_rebuild()
