import logging

from fastapi import APIRouter, Depends, File, Query, UploadFile
from app.utils.pdf_response import pdf_file_response
from sqlalchemy.orm import Session

from app.api.deps import get_current_user
from app.core.exceptions import AppError, ValidationError
from app.db.session import get_db
from app.schemas.policy import PolicyResponse
from app.models.enums import extraction_status_value
from app.schemas.upload import ConfirmExtractionRequest, ExtractionListResponse, InspectPdfResponse
from app.schemas.user_context import CurrentUser
from app.services.upload_service import UploadService

logger = logging.getLogger(__name__)

router = APIRouter()


@router.post("/inspect-pdf", response_model=InspectPdfResponse)
async def inspect_pdf(
    file: UploadFile = File(...),
    current_user: CurrentUser = Depends(get_current_user),
    db: Session = Depends(get_db),
):
    """Read PDF text and detect insurer only when the company display name appears in the file."""
    _ = current_user
    filename = file.filename or "policy.pdf"
    if not filename.lower().endswith(".pdf"):
        raise ValidationError("Only PDF files are allowed")

    content = await file.read()
    from app.core.config import get_settings
    from app.services.scan_keyword_service import ScanKeywordService
    from app.utils.pdf_text import pack_raw_text_fields

    settings = get_settings()
    if len(content) > settings.max_upload_size_bytes:
        raise ValidationError(f"File exceeds {settings.max_upload_size_mb}MB limit")

    text_pack = pack_raw_text_fields(content, allow_ocr=False)
    raw_text = text_pack["raw_text"] or ""
    if len(raw_text.strip()) < 20:
        text_pack = pack_raw_text_fields(content, allow_ocr=True)
        raw_text = text_pack["raw_text"] or ""

    code, name = ScanKeywordService(db).detect_in_text(raw_text)
    logger.debug(
        "inspect-pdf: filename=%s likely=%s company=%s text_source=%s chars=%d",
        filename,
        bool(code and name),
        code,
        text_pack.get("text_source"),
        len(raw_text),
    )
    return InspectPdfResponse(
        company_code=code,
        company_name=name,
        likely_policy=bool(code and name),
    )


@router.post("/pdf")
async def upload_pdf(
    file: UploadFile = File(...),
    current_user: CurrentUser = Depends(get_current_user),
    db: Session = Depends(get_db),
):
    filename = file.filename or "policy.pdf"
    try:
        content = await file.read()
        return UploadService(db).extract_pdf(
            content, filename, current_user.id, current_user.agency_id
        )
    except AppError:
        raise
    except Exception as exc:
        logger.exception(
            "PDF upload failed: %s",
            filename,
            extra={
                "agency_id": current_user.agency_id,
                "user_id": current_user.id,
                "upload_filename": filename,
            },
        )
        raise AppError(
            message=f"PDF upload failed: {exc}",
            code="UPLOAD_FAILED",
            status_code=500,
        ) from exc


@router.post("/pdf/bulk")
async def upload_pdf_bulk(
    files: list[UploadFile] = File(...),
    current_user: CurrentUser = Depends(get_current_user),
    db: Session = Depends(get_db),
):
    service = UploadService(db)
    results = []
    for file in files:
        filename = file.filename or "policy.pdf"
        content = await file.read()
        try:
            result = service.extract_pdf(content, filename, current_user.id, current_user.agency_id)
            results.append({"filename": filename, "success": True, **result})
        except AppError as exc:
            logger.warning(
                "Bulk PDF upload rejected: %s (%s)",
                exc.message,
                filename,
                extra={
                    "agency_id": current_user.agency_id,
                    "user_id": current_user.id,
                    "upload_filename": filename,
                    "error_code": exc.code,
                },
            )
            results.append({"filename": filename, "success": False, "error": exc.message, "code": exc.code})
        except Exception as exc:
            logger.exception(
                "Bulk PDF upload failed: %s",
                filename,
                extra={
                    "agency_id": current_user.agency_id,
                    "user_id": current_user.id,
                    "upload_filename": filename,
                },
            )
            results.append({"filename": filename, "success": False, "error": str(exc), "code": "UPLOAD_FAILED"})
    return {"results": results}


@router.get("/file-checksums")
def list_file_checksums(
    current_user: CurrentUser = Depends(get_current_user),
    db: Session = Depends(get_db),
):
    return UploadService(db).list_known_checksums(current_user.agency_id)


@router.get("/extractions", response_model=ExtractionListResponse)
def list_extractions(
    pending: bool = True,
    page: int = 1,
    page_size: int = 50,
    search: str | None = None,
    status: str | None = None,
    queue_match: str | None = Query(None, pattern="^(new|existing)$"),
    current_user: CurrentUser = Depends(get_current_user),
    db: Session = Depends(get_db),
):
    items, total, new_count, existing_count = UploadService(db).list_extractions(
        current_user.agency_id,
        pending_only=pending,
        page=page,
        page_size=page_size,
        search=search,
        status=status,
        queue_match=queue_match,
    )
    return {
        "items": items,
        "total": total,
        "page": page,
        "page_size": page_size,
        "new_count": new_count,
        "existing_count": existing_count,
    }


@router.get("/extraction/{extraction_id}")
def get_extraction(
    extraction_id: int,
    current_user: CurrentUser = Depends(get_current_user),
    db: Session = Depends(get_db),
):
    service = UploadService(db)
    extraction = service.get_extraction(extraction_id, current_user.agency_id)
    defaults = service.fields_to_form_defaults(extraction, current_user.agency_id)
    summary = service._summary_from_raw_data(extraction.raw_data)
    policy_match = service.resolve_policy_match(current_user.agency_id, summary)
    return {
        "id": extraction.id,
        "status": extraction_status_value(extraction.status),
        "original_filename": extraction.original_filename,
        "policy_id": extraction.policy_id,
        "insurance_company_id": extraction.insurance_company_id,
        "raw_data": extraction.raw_data,
        "form_defaults": defaults,
        "is_new": policy_match is None,
        "policy_match": policy_match,
    }


@router.get("/extraction/{extraction_id}/pdf")
def get_extraction_pdf(
    extraction_id: int,
    current_user: CurrentUser = Depends(get_current_user),
    db: Session = Depends(get_db),
):
    path, filename = UploadService(db).get_extraction_pdf_path(extraction_id, current_user.agency_id)
    return pdf_file_response(path, filename)


@router.post("/extraction/{extraction_id}/confirm", response_model=PolicyResponse)
def confirm_extraction(
    extraction_id: int,
    payload: ConfirmExtractionRequest,
    current_user: CurrentUser = Depends(get_current_user),
    db: Session = Depends(get_db),
):
    return UploadService(db).confirm_extraction(
        current_user.agency_id,
        current_user.id,
        extraction_id,
        payload,
    )


@router.post("/extraction/{extraction_id}/dismiss")
def dismiss_extraction(
    extraction_id: int,
    current_user: CurrentUser = Depends(get_current_user),
    db: Session = Depends(get_db),
):
    return UploadService(db).dismiss_extraction(
        current_user.agency_id,
        current_user.id,
        extraction_id,
    )
