"""Documents router — upload, parse, generate quiz."""
import os
import uuid
from datetime import datetime, timezone

from fastapi import APIRouter, BackgroundTasks, Depends, File, HTTPException, UploadFile
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from app.api.deps import require_roles
from app.core.config import settings
from app.core.logging import get_logger
from app.core.rbac import Role
from app.db.base import get_db
from app.models import (
    DocJobStatus,
    DocumentJob,
    SourceDocument,
    UserModel,
)
from app.schemas import DocumentJobOut, SourceDocumentOut
from app.services.audit import log_audit

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

logger = get_logger("documents")

ALLOWED_EXTENSIONS = {".pdf", ".docx", ".pptx", ".doc", ".ppt"}
MIME_MAP = {
    "application/pdf": "pdf",
    "application/vnd.openxmlformats-officedocument.wordprocessingml.document": "docx",
    "application/vnd.openxmlformats-officedocument.presentationml.presentation": "pptx",
    "application/msword": "doc",
    "application/vnd.ms-powerpoint": "ppt",
}


def detect_file_type(filename: str, content_type: str) -> str:
    ext = os.path.splitext(filename)[1].lower()
    if ext in {".pdf", ".docx", ".pptx", ".doc", ".ppt"}:
        return ext.lstrip(".")
    if content_type in MIME_MAP:
        return MIME_MAP[content_type]
    raise HTTPException(status_code=415, detail=f"Unsupported file type: {ext or content_type}")


@router.post("/documents", response_model=DocumentJobOut, status_code=201)
async def upload_document(
    background_tasks: BackgroundTasks,
    file: UploadFile = File(...),
    db: AsyncSession = Depends(get_db),
    current_user: UserModel = Depends(
        require_roles(Role.LD_ADMIN, Role.DEPT_HEAD, Role.SALES_MANAGER)
    ),
) -> DocumentJobOut:
    """Upload a document for quiz generation."""
    try:
        content = await file.read()
        size_mb = len(content) / (1024 * 1024)
        if size_mb > settings.MAX_UPLOAD_MB:
            raise HTTPException(status_code=413, detail=f"File too large (max {settings.MAX_UPLOAD_MB}MB)")

        file_type = detect_file_type(file.filename or "unknown", file.content_type or "")

        doc_id = uuid.uuid4()
        safe_filename = f"{doc_id}_{file.filename}"
        file_path = os.path.join(settings.UPLOAD_DIR, safe_filename)
        os.makedirs(os.path.dirname(file_path), exist_ok=True)
        with open(file_path, "wb") as f:
            f.write(content)

        doc = SourceDocument(
            id=doc_id,
            filename=file.filename or "upload",
            file_path=file_path,
            file_type=file_type,
            file_size=len(content),
            uploaded_by=current_user.id,
        )
        db.add(doc)

        job_id = uuid.uuid4()
        created_now = datetime.now(timezone.utc)
        job = DocumentJob(
            id=job_id,
            document_id=doc_id,
            status=DocJobStatus.UPLOADED,
            created_at=created_now,
            updated_at=created_now,
        )
        db.add(job)

        await log_audit(db, current_user.id, "document_upload", "document", doc_id,
                        details={"filename": file.filename, "file_type": file_type})

        await db.commit()

        from app.workers.tasks import process_document_job_async
        background_tasks.add_task(process_document_job_async, str(job_id))

        return DocumentJobOut(
            id=job_id,
            document_id=doc_id,
            status="uploaded",
            error_message=None,
            generated_quiz_id=None,
            created_at=created_now,
        )
    except HTTPException:
        await db.rollback()
        raise
    except Exception as e:
        await db.rollback()
        logger.error("upload_document_error", error=str(e))
        raise HTTPException(status_code=500, detail=f"Failed to process document upload: {str(e)}")


@router.get("/documents/{document_id}", response_model=SourceDocumentOut)
async def get_document(
    document_id: uuid.UUID,
    db: AsyncSession = Depends(get_db),
    current_user: UserModel = Depends(require_roles(Role.LD_ADMIN, Role.DEPT_HEAD, Role.SALES_MANAGER)),
) -> SourceDocumentOut:
    doc = await db.get(SourceDocument, document_id)
    if not doc:
        raise HTTPException(status_code=404, detail="Document not found")
    return SourceDocumentOut.model_validate(doc)


@router.post("/documents/{document_id}/generate-quiz", response_model=DocumentJobOut, status_code=202)
async def generate_quiz(
    document_id: uuid.UUID,
    background_tasks: BackgroundTasks,
    db: AsyncSession = Depends(get_db),
    current_user: UserModel = Depends(require_roles(Role.LD_ADMIN, Role.DEPT_HEAD, Role.SALES_MANAGER)),
) -> DocumentJobOut:
    """Trigger AI quiz generation from a parsed document."""
    doc = await db.get(SourceDocument, document_id)
    if not doc:
        raise HTTPException(status_code=404, detail="Document not found")

    # Find or create job
    result = await db.execute(
        select(DocumentJob).where(DocumentJob.document_id == document_id)
    )
    job = result.scalar_one_or_none()
    created_now = datetime.now(timezone.utc)
    if not job:
        job_id = uuid.uuid4()
        job = DocumentJob(
            id=job_id,
            document_id=document_id,
            status=DocJobStatus.GENERATING,
            created_at=created_now,
            updated_at=created_now,
        )
        db.add(job)
    else:
        job_id = job.id
        job.status = DocJobStatus.GENERATING
        created_now = job.created_at or created_now

    await log_audit(db, current_user.id, "quiz_generation_triggered", "document", document_id)
    await db.commit()

    from app.workers.tasks import generate_quiz_from_document_async
    background_tasks.add_task(generate_quiz_from_document_async, str(job_id), str(current_user.id))

    return DocumentJobOut(
        id=job_id,
        document_id=document_id,
        status="generating",
        error_message=None,
        generated_quiz_id=None,
        created_at=created_now,
    )


@router.get("/document-jobs/{job_id}", response_model=DocumentJobOut)
async def get_job_status(
    job_id: uuid.UUID,
    db: AsyncSession = Depends(get_db),
    current_user: UserModel = Depends(require_roles(Role.LD_ADMIN, Role.DEPT_HEAD, Role.SALES_MANAGER)),
) -> DocumentJobOut:
    job = await db.get(DocumentJob, job_id)
    if not job:
        raise HTTPException(status_code=404, detail="Job not found")
    return DocumentJobOut.model_validate(job)


@router.get("/document-jobs", response_model=list[DocumentJobOut])
async def list_job_statuses(
    db: AsyncSession = Depends(get_db),
    current_user: UserModel = Depends(require_roles(Role.LD_ADMIN, Role.DEPT_HEAD, Role.SALES_MANAGER)),
) -> list[DocumentJobOut]:
    result = await db.execute(select(DocumentJob).order_by(DocumentJob.created_at.desc()).limit(20))
    jobs = result.scalars().all()
    return [DocumentJobOut.model_validate(j) for j in jobs]
