"""자료별 손글씨 노트 API.

흐름:
  GET    /api/documents/{id}/note  → 단건 조회 (없으면 strokes_json=None)
  PUT    /api/documents/{id}/note  → upsert (strokes_json + canvas 크기)
  DELETE /api/documents/{id}/note  → 노트 삭제

ownership:
  - documents 에 user_id 부재 (single-user). document_notes.user_id 만으로 분리.
  - GET/PUT/DELETE 모두 WHERE user_id=current_user.id AND document_id=:doc_id.
"""

import logging
from datetime import datetime
from typing import Annotated, Any

from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel
from sqlalchemy import select
from sqlalchemy.dialects.postgresql import insert as pg_insert
from sqlalchemy.ext.asyncio import AsyncSession

from core.auth import get_current_user
from core.database import get_session
from models.document import Document
from models.document_note import DocumentNote
from models.user import User

logger = logging.getLogger(__name__)
router = APIRouter()


class NoteResponse(BaseModel):
    document_id: int
    strokes_json: dict[str, Any] | None
    canvas_width: int | None
    canvas_height: int | None
    schema_version: int
    updated_at: datetime | None
    created_at: datetime | None


class NoteUpdate(BaseModel):
    strokes_json: dict[str, Any] | None = None
    canvas_width: int | None = None
    canvas_height: int | None = None


async def _verify_document(session: AsyncSession, document_id: int) -> Document:
    doc = await session.get(Document, document_id)
    if doc is None or getattr(doc, "deleted_at", None) is not None:
        raise HTTPException(status_code=404, detail="문서를 찾을 수 없습니다")
    return doc


def _empty_response(document_id: int) -> NoteResponse:
    return NoteResponse(
        document_id=document_id,
        strokes_json=None,
        canvas_width=None,
        canvas_height=None,
        schema_version=1,
        updated_at=None,
        created_at=None,
    )


def _to_response(note: DocumentNote) -> NoteResponse:
    return NoteResponse(
        document_id=note.document_id,
        strokes_json=note.strokes_json,
        canvas_width=note.canvas_width,
        canvas_height=note.canvas_height,
        schema_version=note.schema_version,
        updated_at=note.updated_at,
        created_at=note.created_at,
    )


@router.get("/{document_id}/note", response_model=NoteResponse)
async def get_note(
    document_id: int,
    user: Annotated[User, Depends(get_current_user)],
    session: Annotated[AsyncSession, Depends(get_session)],
):
    await _verify_document(session, document_id)
    res = await session.execute(
        select(DocumentNote).where(
            DocumentNote.user_id == user.id,
            DocumentNote.document_id == document_id,
        )
    )
    note = res.scalar_one_or_none()
    if note is None:
        return _empty_response(document_id)
    return _to_response(note)


@router.put("/{document_id}/note", response_model=NoteResponse)
async def upsert_note(
    document_id: int,
    body: NoteUpdate,
    user: Annotated[User, Depends(get_current_user)],
    session: Annotated[AsyncSession, Depends(get_session)],
):
    """upsert — 같은 (user, document) 면 update, 없으면 insert. PostgreSQL ON CONFLICT."""
    await _verify_document(session, document_id)
    values: dict[str, Any] = {
        "user_id": user.id,
        "document_id": document_id,
        "strokes_json": body.strokes_json,
        "canvas_width": body.canvas_width,
        "canvas_height": body.canvas_height,
    }
    stmt = (
        pg_insert(DocumentNote)
        .values(**values)
        .on_conflict_do_update(
            index_elements=["user_id", "document_id"],
            set_={
                "strokes_json": body.strokes_json,
                "canvas_width": body.canvas_width,
                "canvas_height": body.canvas_height,
                "updated_at": datetime.now(),
            },
        )
        .returning(DocumentNote)
    )
    result = await session.execute(stmt)
    note = result.scalar_one()
    await session.commit()
    return _to_response(note)


@router.delete("/{document_id}/note", status_code=204)
async def delete_note(
    document_id: int,
    user: Annotated[User, Depends(get_current_user)],
    session: Annotated[AsyncSession, Depends(get_session)],
):
    await _verify_document(session, document_id)
    res = await session.execute(
        select(DocumentNote).where(
            DocumentNote.user_id == user.id,
            DocumentNote.document_id == document_id,
        )
    )
    note = res.scalar_one_or_none()
    if note is not None:
        await session.delete(note)
        await session.commit()
