"""
Batch Upload API Routes

Endpoints for batch uploading documents via ZIP files with CSV metadata.
"""

import io
import logging
import zipfile
from datetime import datetime
from typing import Annotated
from uuid import UUID

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

from backend.data.repositories import BatchUploadRepository
from backend.web.core.auth import validate_admin_token
from backend.web.services.batch_upload import BatchUploadService, MAX_COMPRESSED_SIZE, MAX_UNCOMPRESSED_SIZE
from backend.web.workers.batch_queue import BatchTask, get_batch_queue

logger = logging.getLogger(__name__)

# Global repository instance
_batch_repo: BatchUploadRepository | None = None


def get_batch_repository() -> BatchUploadRepository:
    """Get the BatchUploadRepository instance."""
    global _batch_repo
    if _batch_repo is None:
        _batch_repo = BatchUploadRepository()
    return _batch_repo


router = APIRouter(prefix="/api/v1/admin/batch", tags=["batch-upload"])


@router.post("/upload")
async def upload_batch(
    file: UploadFile = File(...),
    upload_source: str = Form(default="ui"),
    async_mode: bool = Form(default=True),
    auto_label: bool = Form(default=True),
    admin_token: Annotated[str, Depends(validate_admin_token)] = None,
    batch_repo: Annotated[BatchUploadRepository, Depends(get_batch_repository)] = None,
) -> dict:
    """Upload a batch of documents via ZIP file.

    The ZIP file can contain:
    - Multiple PDF files
    - Optional CSV file with field values for auto-labeling

    CSV format:
    - Required column: DocumentId (matches PDF filename without extension)
    - Optional columns: InvoiceNumber, InvoiceDate, InvoiceDueDate, Amount,
      OCR, Bankgiro, Plusgiro, customer_number, supplier_organisation_number

    Args:
        file: ZIP file upload
        upload_source: Upload source (ui or api)
        admin_token: Admin authentication token
        admin_db: Admin database interface

    Returns:
        Batch upload result with batch_id and status
    """
    if not file.filename.lower().endswith('.zip'):
        raise HTTPException(status_code=400, detail="Only ZIP files are supported")

    # Check compressed size
    if file.size and file.size > MAX_COMPRESSED_SIZE:
        max_mb = MAX_COMPRESSED_SIZE / (1024 * 1024)
        raise HTTPException(
            status_code=400,
            detail=f"File size exceeds {max_mb:.0f}MB limit"
        )

    try:
        # Read file content
        zip_content = await file.read()

        # Additional security validation before processing
        try:
            with zipfile.ZipFile(io.BytesIO(zip_content)) as test_zip:
                # Quick validation of ZIP structure
                test_zip.testzip()
        except zipfile.BadZipFile:
            raise HTTPException(status_code=400, detail="Invalid ZIP file format")

        if async_mode:
            # Async mode: Queue task and return immediately
            from uuid import uuid4

            batch_id = uuid4()

            # Create batch task for background processing
            task = BatchTask(
                batch_id=batch_id,
                admin_token=admin_token,
                zip_content=zip_content,
                zip_filename=file.filename,
                upload_source=upload_source,
                auto_label=auto_label,
                created_at=datetime.utcnow(),
            )

            # Submit to queue
            queue = get_batch_queue()
            if not queue.submit(task):
                raise HTTPException(
                    status_code=503,
                    detail="Processing queue is full. Please try again later."
                )

            logger.info(
                f"Batch upload queued: batch_id={batch_id}, "
                f"filename={file.filename}, async_mode=True"
            )

            # Return 202 Accepted with batch_id and status URL
            return JSONResponse(
                status_code=202,
                content={
                    "status": "accepted",
                    "batch_id": str(batch_id),
                    "message": "Batch upload queued for processing",
                    "status_url": f"/api/v1/admin/batch/status/{batch_id}",
                    "queue_depth": queue.get_queue_depth(),
                }
            )
        else:
            # Sync mode: Process immediately and return results
            service = BatchUploadService(batch_repo)
            result = service.process_zip_upload(
                admin_token=admin_token,
                zip_filename=file.filename,
                zip_content=zip_content,
                upload_source=upload_source,
            )

            logger.info(
                f"Batch upload completed: batch_id={result.get('batch_id')}, "
                f"status={result.get('status')}, files={result.get('successful_files')}"
            )

            return result

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Error processing batch upload: {e}", exc_info=True)
        raise HTTPException(
            status_code=500,
            detail="Failed to process batch upload. Please contact support."
        )


@router.get("/status/{batch_id}")
async def get_batch_status(
    batch_id: str,
    admin_token: Annotated[str, Depends(validate_admin_token)] = None,
    batch_repo: Annotated[BatchUploadRepository, Depends(get_batch_repository)] = None,
) -> dict:
    """Get batch upload status and file processing details.

    Args:
        batch_id: Batch upload ID
        admin_token: Admin authentication token
        batch_repo: Batch upload repository

    Returns:
        Batch status with file processing details
    """
    # Validate UUID format
    try:
        batch_uuid = UUID(batch_id)
    except ValueError:
        raise HTTPException(status_code=400, detail="Invalid batch ID format")

    # Check batch exists and verify ownership
    batch = batch_repo.get(batch_uuid)
    if not batch:
        raise HTTPException(status_code=404, detail="Batch not found")

    # CRITICAL: Verify ownership
    if batch.admin_token != admin_token:
        raise HTTPException(
            status_code=403,
            detail="You do not have access to this batch"
        )

    # Now safe to return details
    service = BatchUploadService(batch_repo)
    result = service.get_batch_status(batch_id)

    return result


@router.get("/list")
async def list_batch_uploads(
    admin_token: Annotated[str, Depends(validate_admin_token)] = None,
    batch_repo: Annotated[BatchUploadRepository, Depends(get_batch_repository)] = None,
    limit: int = 50,
    offset: int = 0,
) -> dict:
    """List batch uploads for the current admin token.

    Args:
        admin_token: Admin authentication token
        batch_repo: Batch upload repository
        limit: Maximum number of results
        offset: Offset for pagination

    Returns:
        List of batch uploads
    """
    # Validate pagination parameters
    if limit < 1 or limit > 100:
        raise HTTPException(status_code=400, detail="Limit must be between 1 and 100")
    if offset < 0:
        raise HTTPException(status_code=400, detail="Offset must be non-negative")

    # Get batch uploads filtered by admin token
    batches, total = batch_repo.get_paginated(
        admin_token=admin_token,
        limit=limit,
        offset=offset,
    )

    return {
        "batches": [
            {
                "batch_id": str(b.batch_id),
                "filename": b.filename,
                "status": b.status,
                "total_files": b.total_files,
                "successful_files": b.successful_files,
                "failed_files": b.failed_files,
                "created_at": b.created_at.isoformat() if b.created_at else None,
                "completed_at": b.completed_at.isoformat() if b.completed_at else None,
            }
            for b in batches
        ],
        "total": total,
        "limit": limit,
        "offset": offset,
    }
