"""
個人儀表板（rdash）任務編輯 API — 蘇煥誠私人用，獨立、token 控管。

設計原則：
  - 完全不碰團隊資料（不進 DB、不用 auth deps），只讀寫
    static/<token>/rdash_tasks.json 這一個檔。
  - token 同時是 static 資料夾名稱（祕密、難猜），等同通行證；
    路徑帶錯 token 一律 404。
  - MVP：列出 / 改名 / 刪除任務。新增、改狀態之後再加。
  - 寫檔用 temp + os.replace 原子寫入，避免半寫壞檔。

掛載：app/main.py 內 `from app.api import rdash as rdash_routes`
      + `app.include_router(rdash_routes.router)`。
出問題只要移除那兩行 + 砍此檔即可完全還原，不影響 Cooper。
"""
import json
import os
import re
from pathlib import Path

from fastapi import APIRouter, HTTPException
from pydantic import BaseModel

router = APIRouter(prefix="/api/rdash", tags=["rdash"])

# app/api/rdash.py -> parent(api) -> parent(app 套件) -> parent(coba/app) / static
_STATIC_DIR = Path(__file__).resolve().parent.parent.parent / "static"
_TOKEN_RE = re.compile(r"^rdash-[A-Za-z0-9_-]{8,}$")


def _store(token: str) -> Path:
    """驗證 token 並回傳該使用者的 rdash_tasks.json 路徑。"""
    if not _TOKEN_RE.match(token):
        raise HTTPException(status_code=404, detail="not found")
    folder = _STATIC_DIR / token
    if not folder.is_dir():
        raise HTTPException(status_code=404, detail="not found")
    return folder / "rdash_tasks.json"


def _load(p: Path):
    if not p.exists():
        return []
    try:
        data = json.loads(p.read_text(encoding="utf-8"))
        return data if isinstance(data, list) else []
    except Exception:
        return []


def _save(p: Path, data) -> None:
    tmp = p.with_suffix(".tmp")
    tmp.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8")
    os.replace(tmp, p)


class RenameBody(BaseModel):
    id: str
    title: str


class DeleteBody(BaseModel):
    id: str


class StatusBody(BaseModel):
    id: str
    status: str
    doneDate: str | None = None


class AddBody(BaseModel):
    title: str
    stream: str | None = None
    quadrant: str = "q2"
    due: str | None = None


class UpdateBody(BaseModel):
    id: str
    title: str | None = None
    stream: str | None = None
    quadrant: str | None = None
    status: str | None = None
    due: str | None = None
    doneDate: str | None = None


_VALID_STATUS = {"todo", "doing", "done"}
_VALID_QUADRANT = {"q1", "q2", "q3", "q4"}


def _next_id(tasks):
    existing = {t.get("id") for t in tasks}
    n = 1
    while f"u{n}" in existing:
        n += 1
    return f"u{n}"


@router.get("/{token}/tasks")
def list_tasks(token: str):
    return {"ok": True, "tasks": _load(_store(token))}


@router.post("/{token}/rename")
def rename_task(token: str, body: RenameBody):
    p = _store(token)
    tasks = _load(p)
    title = (body.title or "").strip()
    if not title:
        raise HTTPException(status_code=400, detail="title empty")
    for t in tasks:
        if t.get("id") == body.id:
            t["title"] = title[:200]
            _save(p, tasks)
            return {"ok": True, "tasks": tasks}
    raise HTTPException(status_code=404, detail="task not found")


@router.post("/{token}/add")
def add_task(token: str, body: AddBody):
    title = (body.title or "").strip()
    if not title:
        raise HTTPException(status_code=400, detail="title empty")
    q = body.quadrant if body.quadrant in _VALID_QUADRANT else "q2"
    p = _store(token)
    tasks = _load(p)
    task = {
        "id": _next_id(tasks),
        "title": title[:200],
        "stream": (body.stream or None),
        "quadrant": q,
        "status": "todo",
        "due": (body.due or None),
    }
    tasks.append(task)
    _save(p, tasks)
    return {"ok": True, "tasks": tasks, "added": task}


@router.post("/{token}/update")
def update_task(token: str, body: UpdateBody):
    """通用欄位更新：只改有帶進來的欄位（title/stream/quadrant/status/due）。"""
    p = _store(token)
    tasks = _load(p)
    for t in tasks:
        if t.get("id") == body.id:
            if body.title is not None:
                ti = body.title.strip()
                if ti:
                    t["title"] = ti[:200]
            if body.quadrant is not None:
                if body.quadrant not in _VALID_QUADRANT:
                    raise HTTPException(status_code=400, detail="bad quadrant")
                t["quadrant"] = body.quadrant
            if body.status is not None:
                if body.status not in _VALID_STATUS:
                    raise HTTPException(status_code=400, detail="bad status")
                t["status"] = body.status
                if body.status == "done":
                    t["doneDate"] = (body.doneDate or "").strip() or t.get("doneDate")
                else:
                    t.pop("doneDate", None)
            if body.stream is not None:
                t["stream"] = body.stream or None
            if body.due is not None:
                t["due"] = body.due or None
            _save(p, tasks)
            return {"ok": True, "tasks": tasks}
    raise HTTPException(status_code=404, detail="task not found")


@router.post("/{token}/status")
def set_status(token: str, body: StatusBody):
    if body.status not in _VALID_STATUS:
        raise HTTPException(status_code=400, detail="bad status")
    p = _store(token)
    tasks = _load(p)
    for t in tasks:
        if t.get("id") == body.id:
            t["status"] = body.status
            if body.status == "done":
                t["doneDate"] = (body.doneDate or "").strip() or None
            else:
                t.pop("doneDate", None)
            _save(p, tasks)
            return {"ok": True, "tasks": tasks}
    raise HTTPException(status_code=404, detail="task not found")


@router.post("/{token}/delete")
def delete_task(token: str, body: DeleteBody):
    p = _store(token)
    tasks = _load(p)
    kept = [t for t in tasks if t.get("id") != body.id]
    if len(kept) == len(tasks):
        raise HTTPException(status_code=404, detail="task not found")
    _save(p, kept)
    return {"ok": True, "tasks": kept}
