"""
Inference API Routes

FastAPI route definitions for the inference API.
"""

from __future__ import annotations

import logging
import shutil
import uuid
from pathlib import Path
from typing import TYPE_CHECKING

from fastapi import APIRouter, File, Form, HTTPException, UploadFile, status
from fastapi.responses import FileResponse

from backend.web.schemas.inference import (
    DetectionResult,
    HealthResponse,
    InferenceResponse,
    InferenceResult,
    LineItemSchema,
    LineItemsResultSchema,
    MathCheckResultSchema,
    VATBreakdownSchema,
    VATSummarySchema,
    VATValidationResultSchema,
)
from backend.web.schemas.common import ErrorResponse
from backend.web.services.storage_helpers import get_storage_helper

if TYPE_CHECKING:
    from backend.web.services import InferenceService
    from backend.web.config import StorageConfig

logger = logging.getLogger(__name__)


def create_inference_router(
    inference_service: "InferenceService",
    storage_config: "StorageConfig",
) -> APIRouter:
    """
    Create API router with inference endpoints.

    Args:
        inference_service: Inference service instance
        storage_config: Storage configuration

    Returns:
        Configured APIRouter
    """
    router = APIRouter(prefix="/api/v1", tags=["inference"])

    @router.get("/health", response_model=HealthResponse)
    async def health_check() -> HealthResponse:
        """Check service health status."""
        return HealthResponse(
            status="healthy",
            model_loaded=inference_service.is_initialized,
            gpu_available=inference_service.gpu_available,
            version="1.0.0",
        )

    @router.post(
        "/infer",
        response_model=InferenceResponse,
        responses={
            400: {"model": ErrorResponse, "description": "Invalid file"},
            500: {"model": ErrorResponse, "description": "Processing error"},
        },
    )
    async def infer_document(
        file: UploadFile = File(..., description="PDF or image file to process"),
        extract_line_items: bool = Form(
            default=False,
            description="Extract line items and VAT information (business features)",
        ),
    ) -> InferenceResponse:
        """
        Process a document and extract invoice fields.

        Accepts PDF or image files (PNG, JPG, JPEG).
        Returns extracted field values with confidence scores.

        When extract_line_items=True, also extracts:
        - Line items (products/services with quantities and amounts)
        - VAT summary (multiple tax rates breakdown)
        - VAT validation (cross-validation results)
        """
        # Validate file extension
        if not file.filename:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Filename is required",
            )

        file_ext = Path(file.filename).suffix.lower()
        if file_ext not in storage_config.allowed_extensions:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=f"Unsupported file type: {file_ext}. Allowed: {storage_config.allowed_extensions}",
            )

        # Generate document ID
        doc_id = str(uuid.uuid4())[:8]

        # Get storage helper and uploads directory
        storage = get_storage_helper()
        uploads_dir = storage.get_uploads_base_path(subfolder="inference")
        if uploads_dir is None:
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="Storage not configured for local access",
            )

        # Save uploaded file to temporary location for processing
        upload_path = uploads_dir / f"{doc_id}{file_ext}"
        try:
            with open(upload_path, "wb") as f:
                shutil.copyfileobj(file.file, f)
        except Exception as e:
            logger.error(f"Failed to save uploaded file: {e}")
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="Failed to save uploaded file",
            )

        try:
            # Process based on file type
            if file_ext == ".pdf":
                service_result = inference_service.process_pdf(
                    upload_path,
                    document_id=doc_id,
                    extract_line_items=extract_line_items,
                )
            else:
                service_result = inference_service.process_image(
                    upload_path, document_id=doc_id
                )

            # Build response
            viz_url = None
            if service_result.visualization_path:
                viz_url = f"/api/v1/results/{service_result.visualization_path.name}"

            # Build business features schemas if present
            line_items_schema = None
            vat_summary_schema = None
            vat_validation_schema = None

            if service_result.line_items:
                line_items_schema = LineItemsResultSchema(
                    items=[LineItemSchema(**item) for item in service_result.line_items.get("items", [])],
                    header_row=service_result.line_items.get("header_row", []),
                    total_amount=service_result.line_items.get("total_amount"),
                )

            if service_result.vat_summary:
                vat_summary_schema = VATSummarySchema(
                    breakdowns=[VATBreakdownSchema(**b) for b in service_result.vat_summary.get("breakdowns", [])],
                    total_excl_vat=service_result.vat_summary.get("total_excl_vat"),
                    total_vat=service_result.vat_summary.get("total_vat"),
                    total_incl_vat=service_result.vat_summary.get("total_incl_vat"),
                    confidence=service_result.vat_summary.get("confidence", 0.0),
                )

            if service_result.vat_validation:
                vat_validation_schema = VATValidationResultSchema(
                    is_valid=service_result.vat_validation.get("is_valid", False),
                    confidence_score=service_result.vat_validation.get("confidence_score", 0.0),
                    math_checks=[MathCheckResultSchema(**m) for m in service_result.vat_validation.get("math_checks", [])],
                    total_check=service_result.vat_validation.get("total_check", False),
                    line_items_vs_summary=service_result.vat_validation.get("line_items_vs_summary"),
                    amount_consistency=service_result.vat_validation.get("amount_consistency"),
                    needs_review=service_result.vat_validation.get("needs_review", False),
                    review_reasons=service_result.vat_validation.get("review_reasons", []),
                )

            inference_result = InferenceResult(
                document_id=service_result.document_id,
                success=service_result.success,
                document_type=service_result.document_type,
                fields=service_result.fields,
                confidence=service_result.confidence,
                detections=[
                    DetectionResult(**d) for d in service_result.detections
                ],
                processing_time_ms=service_result.processing_time_ms,
                visualization_url=viz_url,
                errors=service_result.errors,
                line_items=line_items_schema,
                vat_summary=vat_summary_schema,
                vat_validation=vat_validation_schema,
            )

            return InferenceResponse(
                status="success" if service_result.success else "partial",
                message=f"Processed document {doc_id}",
                result=inference_result,
            )

        except Exception as e:
            logger.error(f"Error processing document: {e}")
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail=str(e),
            )

        finally:
            # Cleanup uploaded file
            upload_path.unlink(missing_ok=True)

    @router.get("/results/{filename}", response_model=None)
    async def get_result_image(filename: str) -> FileResponse:
        """Get visualization result image."""
        storage = get_storage_helper()
        file_path = storage.get_result_local_path(filename)

        if file_path is None:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail=f"Result file not found: {filename}",
            )

        return FileResponse(
            path=file_path,
            media_type="image/png",
            filename=filename,
        )

    @router.delete("/results/{filename}")
    async def delete_result(filename: str) -> dict:
        """Delete a result file."""
        storage = get_storage_helper()

        if not storage.result_exists(filename):
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail=f"Result file not found: {filename}",
            )

        storage.delete_result(filename)
        return {"status": "deleted", "filename": filename}

    return router
