import os
import uuid
import shutil

from fastapi import APIRouter, Depends, HTTPException, UploadFile, File, status
from sqlalchemy.orm import Session

from app.config import settings
from app.database import get_db
from app.models.pdf_document import PDFDocument
from app.models.section import Section
from app.models.user import User
from app.schemas.document import DocumentResponse, DocumentStatusResponse, SectionCreate, SectionResponse
from app.utils.auth import get_current_user, require_moderator
from app.services import vector_service

router = APIRouter()


@router.post("/upload", response_model=DocumentResponse)
def upload_document(
    file: UploadFile = File(...),
    db: Session = Depends(get_db),
    current_user: User = Depends(require_moderator),
):
    if not file.filename or not file.filename.lower().endswith(".pdf"):
        raise HTTPException(status_code=400, detail="Only PDF files are accepted")

    # Save file to disk streaming (handles large files)
    os.makedirs(settings.UPLOAD_DIR, exist_ok=True)
    safe_name = f"{uuid.uuid4()}_{os.path.basename(file.filename)}"
    file_path = os.path.join(settings.UPLOAD_DIR, safe_name)

    with open(file_path, "wb") as buffer:
        shutil.copyfileobj(file.file, buffer, length=1024 * 1024)

    # Check file size
    file_size = os.path.getsize(file_path)
    if file_size > settings.MAX_UPLOAD_SIZE:
        os.remove(file_path)
        raise HTTPException(status_code=400, detail=f"File too large. Max size: {settings.MAX_UPLOAD_SIZE} bytes")

    # Create DB record
    doc = PDFDocument(
        user_id=current_user.id,
        filename=safe_name,
        original_filename=file.filename,
        status="processing",
    )
    db.add(doc)
    db.commit()
    db.refresh(doc)

    # Dispatch background processing
    try:
        from app.tasks.pdf_tasks import process_pdf
        process_pdf.delay(doc.id, file_path)
    except Exception:
        # If Celery/Redis not available, process synchronously
        from app.services import pdf_service
        try:
            total_pages = pdf_service.get_page_count(file_path)
            doc.total_pages = total_pages
            pages = pdf_service.extract_text_by_page(file_path)
            if pages:
                vector_service.store_pages(doc.id, pages)
                doc.status = "ready"
            else:
                doc.status = "error"
                doc.error_message = "No text could be extracted"
            db.commit()
        except Exception as e:
            doc.status = "error"
            doc.error_message = str(e)[:500]
            db.commit()

    db.refresh(doc)
    return doc


@router.get("/", response_model=list[DocumentResponse])
def list_documents(
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    if current_user.is_moderator:
        docs = db.query(PDFDocument).order_by(PDFDocument.uploaded_at.desc()).all()
    else:
        docs = db.query(PDFDocument).filter(PDFDocument.user_id == current_user.id).order_by(PDFDocument.uploaded_at.desc()).all()
    return docs


def _get_doc_or_404(document_id: int, current_user: User, db) -> PDFDocument:
    """Fetch document; moderators can access any, users only their own."""
    query = db.query(PDFDocument).filter(PDFDocument.id == document_id)
    if not current_user.is_moderator:
        query = query.filter(PDFDocument.user_id == current_user.id)
    doc = query.first()
    if not doc:
        raise HTTPException(status_code=404, detail="Document not found")
    return doc


@router.get("/{document_id}", response_model=DocumentResponse)
def get_document(
    document_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    return _get_doc_or_404(document_id, current_user, db)


@router.get("/{document_id}/status", response_model=DocumentStatusResponse)
def get_document_status(
    document_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    doc = _get_doc_or_404(document_id, current_user, db)
    return DocumentStatusResponse(
        id=doc.id,
        status=doc.status,
        total_pages=doc.total_pages,
        error_message=doc.error_message,
    )


@router.get("/{document_id}/processing-steps")
def get_processing_steps(
    document_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """Poll PDF processing progress steps from Redis."""
    _get_doc_or_404(document_id, current_user, db)
    import json as _json
    import redis
    r = redis.from_url(settings.REDIS_URL, decode_responses=True)
    raw = r.lrange(f"pdf:steps:{document_id}", 0, -1)
    steps = [_json.loads(s) for s in raw] if raw else []
    return {"steps": steps}


@router.post("/{document_id}/sections", response_model=SectionResponse)
def create_section(
    document_id: int,
    section_data: SectionCreate,
    db: Session = Depends(get_db),
    current_user: User = Depends(require_moderator),
):
    doc = _get_doc_or_404(document_id, current_user, db)
    if not doc:
        raise HTTPException(status_code=404, detail="Document not found")
    if doc.status != "ready":
        raise HTTPException(status_code=400, detail="Document is not ready yet")
    if section_data.start_page < 1 or section_data.end_page < 1:
        raise HTTPException(status_code=400, detail="Page numbers must be positive")
    if section_data.start_page >= section_data.end_page:
        raise HTTPException(status_code=400, detail="start_page must be less than end_page")
    if doc.total_pages and section_data.end_page > doc.total_pages:
        raise HTTPException(status_code=400, detail=f"end_page exceeds document length ({doc.total_pages} pages)")

    section = Section(
        document_id=document_id,
        name=section_data.name,
        start_page=section_data.start_page,
        end_page=section_data.end_page,
    )
    db.add(section)
    db.commit()
    db.refresh(section)
    return section


@router.delete("/{document_id}/sections/{section_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_section(
    document_id: int,
    section_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(require_moderator),
):
    doc = _get_doc_or_404(document_id, current_user, db)
    section = db.query(Section).filter(Section.id == section_id, Section.document_id == document_id).first()
    if not section:
        raise HTTPException(status_code=404, detail="Section not found")
    db.delete(section)
    db.commit()


@router.delete("/{document_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_document(
    document_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(require_moderator),
):
    doc = _get_doc_or_404(document_id, current_user, db)

    # Delete file
    file_path = os.path.join(settings.UPLOAD_DIR, doc.filename)
    if os.path.exists(file_path):
        os.remove(file_path)

    # Delete ChromaDB collection
    vector_service.delete_collection(document_id)

    db.delete(doc)
    db.commit()
