# backend/app/routers/inbox.py
import uuid

from fastapi import APIRouter, Depends, File, Form, HTTPException, UploadFile
from sqlmodel import Session, select

from ..auth.deps import current_user
from ..auth.scope import scoped
from ..db import get_session
from ..llm.provider import LLMProvider, get_provider
from ..models import (
    InboxClassification,
    InboxItem,
    InboxStatus,
    Person,
    Prio,
    Project,
    Task,
    TaskStatus,
)
from ..multimodal.factory import get_stt, get_vision
from ..routers.tasks import to_node
from ..schemas import (
    CaptionOut,
    CaptureRequest,
    CaptureResponse,
    ClassificationOut,
    ConfirmResponse,
    InboxItemOut,
    ReclassifyRequest,
    TranscribeOut,
)
from ..services.classification import classify, persist_classification

router = APIRouter()  # prefix 없음. main.py 에서 prefix="/api" 등록.


# ── phase-14: 멀티모달 캡처(음성→텍스트 / 이미지→캡션). 분류 경로는 phase-4 capture 재사용. ──
@router.post("/inbox/transcribe", response_model=TranscribeOut)
async def transcribe(audio: UploadFile = File(...), hint: str = Form("")):
    data = await audio.read()
    t = get_stt().transcribe(data, mime=audio.content_type or "audio/webm", hint=hint)
    return TranscribeOut(text=t.text, seconds=t.seconds, model=t.model, confidence=t.confidence)


@router.post("/inbox/caption", response_model=CaptionOut)
async def caption(image: UploadFile = File(...), hint: str = Form("")):
    data = await image.read()
    c = get_vision().describe(data, mime=image.content_type or "image/jpeg", hint=hint)
    return CaptionOut(text=c.text, ocr=c.ocr, model=c.model, confidence=c.confidence)


def latest_cls(s: Session, item_id: str) -> InboxClassification | None:
    # id 가 TEXT PK(UUID)라 정렬 키로 부적합 → created_at 기준 최신.
    rows = s.exec(
        select(InboxClassification)
        .where(InboxClassification.inbox_item_id == item_id)
        .order_by(InboxClassification.created_at.desc())
    ).all()
    return rows[0] if rows else None


def item_out(s: Session, item: InboxItem) -> InboxItemOut:
    c = latest_cls(s, item.id)
    cls = ClassificationOut.model_validate(c, from_attributes=True) if c else None
    return InboxItemOut(
        id=item.id,
        kind=item.kind,
        raw=item.raw,
        status=item.status,
        created_at=item.created_at,
        materialized_task_id=item.materialized_task_id,
        classification=cls,
    )


@router.get("/inbox", response_model=list[InboxItemOut])
def list_inbox(s: Session = Depends(get_session), user: Person = Depends(current_user)):
    items = s.exec(
        scoped(select(InboxItem), InboxItem, user.id).order_by(InboxItem.created_at.desc())
    ).all()
    return [item_out(s, it) for it in items]


@router.post("/inbox/capture", response_model=CaptureResponse)
def capture(
    body: CaptureRequest,
    s: Session = Depends(get_session),
    provider: LLMProvider = Depends(get_provider),
    user: Person = Depends(current_user),
):
    iid = "s-" + uuid.uuid4().hex[:8]
    item = InboxItem(id=iid, user_id=user.id, kind=body.kind, raw=body.raw, status=InboxStatus.new)
    s.add(item)
    s.commit()
    s.refresh(item)
    c = classify(s, body.raw, provider)  # 동기 분류 (LLM or 폴백)
    row = persist_classification(s, iid, c)
    item.status = InboxStatus.classified
    s.add(item)
    s.commit()
    return CaptureResponse(
        item=item_out(s, item),
        classification=ClassificationOut.model_validate(row, from_attributes=True),
    )


@router.post("/inbox/{iid}/reclassify", response_model=ClassificationOut)
def reclassify(
    iid: str,
    body: ReclassifyRequest,
    s: Session = Depends(get_session),
    provider: LLMProvider = Depends(get_provider),
):
    item = s.get(InboxItem, iid)
    if not item:
        raise HTTPException(404, "inbox item not found")
    c = classify(s, item.raw, provider, force_type=body.type.value if body.type else None)
    row = persist_classification(s, iid, c)  # 새 row → latest 가 최신
    item.status = InboxStatus.classified
    s.add(item)
    s.commit()
    return ClassificationOut.model_validate(row, from_attributes=True)


@router.post("/inbox/{iid}/confirm", response_model=ConfirmResponse)
def confirm(iid: str, s: Session = Depends(get_session)):
    item = s.get(InboxItem, iid)
    if not item:
        raise HTTPException(404, "inbox item not found")
    # 멱등: 이미 confirmed 면 중복 실체화하지 않고 현재 상태만 반환
    if item.status == InboxStatus.confirmed:
        return ConfirmResponse(item=item_out(s, item), task=None)
    c = latest_cls(s, iid)
    if not c:
        raise HTTPException(400, "no classification to confirm")

    created: Task | None = None
    ctype = c.type.value if hasattr(c.type, "value") else c.type
    csphere = c.sphere.value if hasattr(c.sphere, "value") else c.sphere
    if ctype == "task":
        # 프로젝트 결정: classification.project_id 있으면 그대로, 없으면 sphere 기본
        pid = c.project_id
        if not pid or not s.get(Project, pid):
            pid = "me" if csphere == "life" else _fallback_work_project(s)
        # confirm task 필드 정본(R10)
        notes = "스마트 인박스에서 실체화된 작업이에요."
        if c.extra:
            notes += " " + c.extra  # 예: 비행기 티켓 → "가격 추적 알림 켜둠"
        tid = "t-" + uuid.uuid4().hex[:8]
        created = Task(
            id=tid,
            title=item.raw,
            project_id=pid,
            status=TaskStatus.todo,
            assignee_id="jiwoo",
            prio=Prio.normal,
            due=None,
            notes=notes,
        )
        s.add(created)
        s.commit()
        s.refresh(created)
        item.materialized_task_id = tid

    item.status = InboxStatus.confirmed
    s.add(item)
    s.commit()
    node = to_node(s, created, s.exec(select(Task)).all()) if created else None
    return ConfirmResponse(item=item_out(s, item), task=node)


@router.post("/inbox/{iid}/dismiss", response_model=InboxItemOut)
def dismiss(iid: str, s: Session = Depends(get_session)):
    item = s.get(InboxItem, iid)
    if not item:
        raise HTTPException(404, "inbox item not found")
    item.status = InboxStatus.dismissed
    s.add(item)
    s.commit()
    return item_out(s, item)


def _fallback_work_project(s: Session) -> str:
    p = s.exec(select(Project).where(Project.folder_id == "work")).first()
    return p.id if p else "me"
