"""API routes for review notes - timestamped notes on video assets during review."""

from datetime import datetime

from bson import ObjectId
from fastapi import APIRouter, Depends, HTTPException, Query, status
from motor.motor_asyncio import AsyncIOMotorDatabase

from ...core.authz import MembershipContext, get_job_or_403, get_membership_context
from ...core.database import get_database
from ...core.dependencies import require_roles
from ...core.logging import get_logger
from ...models.user import User, UserRole
from ...schemas.review_note import (
    ReviewNoteCreateRequest,
    ReviewNoteResponse,
    ReviewNotesListResponse,
    ReviewNoteUpdateRequest,
)

logger = get_logger(__name__)
router = APIRouter(prefix="/jobs/{job_id}/review-notes", tags=["review-notes"])


@router.get("", response_model=ReviewNotesListResponse)
async def list_review_notes(
    job_id: str,
    asset_key: str | None = Query(None, description="Filter notes by asset key"),
    current_user: User = Depends(require_roles(UserRole.REVIEWER, UserRole.LINGUIST, UserRole.PRODUCTION, UserRole.ADMIN)),
    ctx: MembershipContext = Depends(get_membership_context),
    db: AsyncIOMotorDatabase = Depends(get_database),
):
    """List all review notes for a job, optionally filtered by asset key."""
    await get_job_or_403(job_id, ctx, db)  # org check + existence check

    # Build query
    query = {"job_id": job_id}
    if asset_key:
        query["asset_key"] = asset_key

    # Fetch notes sorted by timestamp
    cursor = db.review_notes.find(query).sort("timestamp_seconds", 1)
    notes = await cursor.to_list(length=1000)

    return ReviewNotesListResponse(
        notes=[ReviewNoteResponse.from_model(note) for note in notes],
        total=len(notes)
    )


@router.post("", response_model=ReviewNoteResponse, status_code=status.HTTP_201_CREATED)
async def create_review_note(
    job_id: str,
    request: ReviewNoteCreateRequest,
    current_user: User = Depends(require_roles(UserRole.REVIEWER, UserRole.LINGUIST, UserRole.PRODUCTION, UserRole.ADMIN)),
    ctx: MembershipContext = Depends(get_membership_context),
    db: AsyncIOMotorDatabase = Depends(get_database),
):
    """Create a new review note for a video asset."""
    await get_job_or_403(job_id, ctx, db)  # org check + existence check

    # Create note document
    note_id = str(ObjectId())
    now = datetime.utcnow()

    note_data = {
        "_id": note_id,
        "job_id": job_id,
        "asset_key": request.asset_key,
        "timestamp_seconds": request.timestamp_seconds,
        "content": request.content,
        "user_id": str(current_user.id),
        "user_name": current_user.full_name,
        "created_at": now,
        "updated_at": None,
    }

    await db.review_notes.insert_one(note_data)
    logger.info(f"Created review note {note_id} for job {job_id} at {request.timestamp_seconds}s")

    return ReviewNoteResponse.from_model(note_data)


@router.get("/{note_id}", response_model=ReviewNoteResponse)
async def get_review_note(
    job_id: str,
    note_id: str,
    current_user: User = Depends(require_roles(UserRole.REVIEWER, UserRole.LINGUIST, UserRole.PRODUCTION, UserRole.ADMIN)),
    ctx: MembershipContext = Depends(get_membership_context),
    db: AsyncIOMotorDatabase = Depends(get_database),
):
    """Get a single review note by ID."""
    await get_job_or_403(job_id, ctx, db)  # org check
    note = await db.review_notes.find_one({"_id": note_id, "job_id": job_id})
    if not note:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Note not found"
        )

    return ReviewNoteResponse.from_model(note)


@router.patch("/{note_id}", response_model=ReviewNoteResponse)
async def update_review_note(
    job_id: str,
    note_id: str,
    request: ReviewNoteUpdateRequest,
    current_user: User = Depends(require_roles(UserRole.REVIEWER, UserRole.LINGUIST, UserRole.PRODUCTION, UserRole.ADMIN)),
    ctx: MembershipContext = Depends(get_membership_context),
    db: AsyncIOMotorDatabase = Depends(get_database),
):
    """Update a review note. Only the note owner can update."""
    await get_job_or_403(job_id, ctx, db)  # org check
    note = await db.review_notes.find_one({"_id": note_id, "job_id": job_id})
    if not note:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Note not found"
        )

    # Check ownership (allow admin to bypass)
    if note["user_id"] != str(current_user.id) and current_user.role != UserRole.ADMIN:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="You can only edit your own notes"
        )

    # Update note
    now = datetime.utcnow()
    await db.review_notes.update_one(
        {"_id": note_id},
        {"$set": {"content": request.content, "updated_at": now}}
    )

    # Fetch updated note
    updated_note = await db.review_notes.find_one({"_id": note_id})
    logger.info(f"Updated review note {note_id}")

    return ReviewNoteResponse.from_model(updated_note)


@router.delete("/{note_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_review_note(
    job_id: str,
    note_id: str,
    current_user: User = Depends(require_roles(UserRole.REVIEWER, UserRole.LINGUIST, UserRole.PRODUCTION, UserRole.ADMIN)),
    ctx: MembershipContext = Depends(get_membership_context),
    db: AsyncIOMotorDatabase = Depends(get_database),
):
    """Delete a review note. Only the note owner can delete."""
    await get_job_or_403(job_id, ctx, db)  # org check
    note = await db.review_notes.find_one({"_id": note_id, "job_id": job_id})
    if not note:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Note not found"
        )

    # Check ownership (allow admin to bypass)
    if note["user_id"] != str(current_user.id) and current_user.role != UserRole.ADMIN:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="You can only delete your own notes"
        )

    await db.review_notes.delete_one({"_id": note_id})
    logger.info(f"Deleted review note {note_id}")

    return None
