"""Documents router for BadNote — upload, download, annotations, bookmarks."""

import json
from datetime import datetime, timezone
from uuid import uuid4

from fastapi import APIRouter, Depends, HTTPException, UploadFile, File, Form, status
from fastapi.responses import FileResponse

from ..auth import get_current_user
from ..database import get_db
from ..models import (
    AnnotationResponse,
    AnnotationUpdate,
    BookmarkCreate,
    BookmarkResponse,
    DocumentResponse,
)
from ..storage import delete_document, get_document_path, save_document

router = APIRouter()


def _row_to_doc(row) -> DocumentResponse:
    return DocumentResponse(
        id=row["id"],
        user_id=row["user_id"],
        filename=row["filename"],
        doc_type=row["doc_type"],
        page_count=row["page_count"],
        created_at=row["created_at"],
        updated_at=row["updated_at"],
    )


# ── Documents ───────────────────────────────────────────────────────────────


@router.post("/upload", response_model=DocumentResponse, status_code=status.HTTP_201_CREATED)
async def upload_document(
    file: UploadFile = File(...),
    doc_type: str = Form("pdf"),
    page_count: int = Form(0),
    user_id: str = Depends(get_current_user),
) -> DocumentResponse:
    """Upload a document file."""
    doc_id = str(uuid4())
    now = datetime.now(timezone.utc).isoformat()
    filename = file.filename or "document"
    file_bytes = await file.read()
    file_path = save_document(file_bytes, doc_id, filename)

    db = await get_db()
    await db.execute(
        """INSERT INTO documents (id, user_id, filename, doc_type, file_path, page_count, created_at, updated_at)
           VALUES (?, ?, ?, ?, ?, ?, ?, ?)""",
        (doc_id, user_id, filename, doc_type, file_path, page_count, now, now),
    )
    await db.commit()

    cursor = await db.execute("SELECT * FROM documents WHERE id = ?", (doc_id,))
    row = await cursor.fetchone()
    return _row_to_doc(row)


@router.get("", response_model=list[DocumentResponse])
async def list_documents(
    user_id: str = Depends(get_current_user),
) -> list[DocumentResponse]:
    """List all documents for the current user."""
    db = await get_db()
    cursor = await db.execute(
        "SELECT * FROM documents WHERE user_id = ? ORDER BY created_at DESC",
        (user_id,),
    )
    rows = await cursor.fetchall()
    return [_row_to_doc(r) for r in rows]


@router.get("/{doc_id}", response_model=DocumentResponse)
async def get_document(
    doc_id: str,
    user_id: str = Depends(get_current_user),
) -> DocumentResponse:
    """Get document metadata."""
    db = await get_db()
    cursor = await db.execute(
        "SELECT * FROM documents WHERE id = ? AND user_id = ?", (doc_id, user_id)
    )
    row = await cursor.fetchone()
    if row is None:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Document not found")
    return _row_to_doc(row)


@router.get("/{doc_id}/file")
async def download_document(
    doc_id: str,
    user_id: str = Depends(get_current_user),
) -> FileResponse:
    """Stream document file download."""
    db = await get_db()
    cursor = await db.execute(
        "SELECT * FROM documents WHERE id = ? AND user_id = ?", (doc_id, user_id)
    )
    row = await cursor.fetchone()
    if row is None:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Document not found")

    file_path = row["file_path"]
    return FileResponse(path=file_path, filename=row["filename"], media_type="application/octet-stream")


@router.delete("/{doc_id}", status_code=status.HTTP_200_OK)
async def delete_document_endpoint(
    doc_id: str,
    user_id: str = Depends(get_current_user),
) -> dict:
    """Delete document, its file, annotations, and bookmarks."""
    db = await get_db()
    cursor = await db.execute(
        "SELECT id FROM documents WHERE id = ? AND user_id = ?", (doc_id, user_id)
    )
    if await cursor.fetchone() is None:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Document not found")

    delete_document(doc_id)
    await db.execute("DELETE FROM documents WHERE id = ?", (doc_id,))
    await db.commit()
    return {"deleted": doc_id}


# ── Annotations ─────────────────────────────────────────────────────────────


@router.get("/{doc_id}/annotations", response_model=list[AnnotationResponse])
async def list_annotations(
    doc_id: str,
    user_id: str = Depends(get_current_user),
) -> list[AnnotationResponse]:
    """Get all annotations for a document."""
    db = await get_db()
    # Verify document ownership
    cursor = await db.execute(
        "SELECT id FROM documents WHERE id = ? AND user_id = ?", (doc_id, user_id)
    )
    if await cursor.fetchone() is None:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Document not found")

    cursor = await db.execute(
        "SELECT * FROM annotations WHERE document_id = ? ORDER BY page_number",
        (doc_id,),
    )
    rows = await cursor.fetchall()
    return [
        AnnotationResponse(
            id=r["id"],
            document_id=r["document_id"],
            page_number=r["page_number"],
            annotation_json=json.loads(r["annotation_json"]),
            created_at=r["created_at"],
            updated_at=r["updated_at"],
        )
        for r in rows
    ]


@router.put("/{doc_id}/annotations/{page}", response_model=AnnotationResponse, status_code=status.HTTP_200_OK)
async def update_annotation(
    doc_id: str,
    page: int,
    body: AnnotationUpdate,
    user_id: str = Depends(get_current_user),
) -> AnnotationResponse:
    """Create or replace annotations for a page."""
    db = await get_db()
    cursor = await db.execute(
        "SELECT id FROM documents WHERE id = ? AND user_id = ?", (doc_id, user_id)
    )
    if await cursor.fetchone() is None:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Document not found")

    now = datetime.now(timezone.utc).isoformat()
    annotation_json = json.dumps(body.annotation_json)

    # Check if annotation for this page already exists
    cursor = await db.execute(
        "SELECT id FROM annotations WHERE document_id = ? AND page_number = ?",
        (doc_id, page),
    )
    existing = await cursor.fetchone()

    if existing:
        ann_id = existing["id"]
        await db.execute(
            "UPDATE annotations SET annotation_json = ?, updated_at = ? WHERE id = ?",
            (annotation_json, now, ann_id),
        )
    else:
        ann_id = str(uuid4())
        await db.execute(
            """INSERT INTO annotations (id, document_id, page_number, annotation_json, created_at, updated_at)
               VALUES (?, ?, ?, ?, ?, ?)""",
            (ann_id, doc_id, page, annotation_json, now, now),
        )
    await db.commit()

    cursor = await db.execute("SELECT * FROM annotations WHERE id = ?", (ann_id,))
    row = await cursor.fetchone()
    return AnnotationResponse(
        id=row["id"],
        document_id=row["document_id"],
        page_number=row["page_number"],
        annotation_json=json.loads(row["annotation_json"]),
        created_at=row["created_at"],
        updated_at=row["updated_at"],
    )


# ── Bookmarks ───────────────────────────────────────────────────────────────


@router.get("/{doc_id}/bookmarks", response_model=list[BookmarkResponse])
async def list_bookmarks(
    doc_id: str,
    user_id: str = Depends(get_current_user),
) -> list[BookmarkResponse]:
    """Get all bookmarks for a document."""
    db = await get_db()
    cursor = await db.execute(
        "SELECT id FROM documents WHERE id = ? AND user_id = ?", (doc_id, user_id)
    )
    if await cursor.fetchone() is None:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Document not found")

    cursor = await db.execute(
        "SELECT * FROM bookmarks WHERE document_id = ? ORDER BY page_number",
        (doc_id,),
    )
    rows = await cursor.fetchall()
    return [
        BookmarkResponse(
            id=r["id"],
            document_id=r["document_id"],
            page_number=r["page_number"],
            label=r["label"],
            color=r["color"],
            created_at=r["created_at"],
        )
        for r in rows
    ]


@router.post("/{doc_id}/bookmarks", response_model=BookmarkResponse, status_code=status.HTTP_201_CREATED)
async def create_bookmark(
    doc_id: str,
    body: BookmarkCreate,
    user_id: str = Depends(get_current_user),
) -> BookmarkResponse:
    """Add a bookmark to a document."""
    db = await get_db()
    cursor = await db.execute(
        "SELECT id FROM documents WHERE id = ? AND user_id = ?", (doc_id, user_id)
    )
    if await cursor.fetchone() is None:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Document not found")

    bookmark_id = str(uuid4())
    now = datetime.now(timezone.utc).isoformat()
    await db.execute(
        """INSERT INTO bookmarks (id, document_id, page_number, label, color, created_at)
           VALUES (?, ?, ?, ?, ?, ?)""",
        (bookmark_id, doc_id, body.page_number, body.label, body.color, now),
    )
    await db.commit()

    return BookmarkResponse(
        id=bookmark_id,
        document_id=doc_id,
        page_number=body.page_number,
        label=body.label,
        color=body.color,
        created_at=now,
    )


@router.delete("/{doc_id}/bookmarks/{bookmark_id}", status_code=status.HTTP_200_OK)
async def delete_bookmark(
    doc_id: str,
    bookmark_id: str,
    user_id: str = Depends(get_current_user),
) -> dict:
    """Delete a bookmark."""
    db = await get_db()
    cursor = await db.execute(
        "SELECT id FROM documents WHERE id = ? AND user_id = ?", (doc_id, user_id)
    )
    if await cursor.fetchone() is None:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Document not found")

    cursor = await db.execute(
        "SELECT id FROM bookmarks WHERE id = ? AND document_id = ?",
        (bookmark_id, doc_id),
    )
    if await cursor.fetchone() is None:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Bookmark not found")

    await db.execute("DELETE FROM bookmarks WHERE id = ?", (bookmark_id,))
    await db.commit()
    return {"deleted": bookmark_id}
