"""Batch file validation service for document uploads.

This module provides batch-level validation for multiple file uploads,
checking constraints like file count and total batch size before
individual file processing begins.
"""

import structlog
from fastapi import UploadFile

logger = structlog.get_logger(__name__)

# Batch validation constants
MAX_FILES_PER_BATCH = 20
MAX_BATCH_SIZE_MB = 500
MAX_BATCH_SIZE_BYTES = MAX_BATCH_SIZE_MB * 1024 * 1024


class BatchValidationError(Exception):
    """Exception raised when batch-level validation fails.

    Attributes:
        code: Error code identifying the type of validation failure.
        message: Human-readable error message.
    """

    def __init__(self, code: str, message: str):
        """Initialize batch validation error.

        Args:
            code: Error code (e.g., "TOO_MANY_FILES", "BATCH_TOO_LARGE").
            message: Human-readable error message.
        """
        self.code = code
        self.message = message
        super().__init__(message)


async def validate_batch_file_count(files: list[UploadFile]) -> None:
    """Validate that batch doesn't exceed maximum file count.

    Args:
        files: List of uploaded files to validate.

    Raises:
        BatchValidationError: If file count exceeds MAX_FILES_PER_BATCH (20).
    """
    file_count = len(files)

    if file_count == 0:
        logger.warning("batch_validation_failed", error="empty_batch", file_count=0)
        raise BatchValidationError(
            code="EMPTY_BATCH",
            message="No files provided in batch upload",
        )

    if file_count > MAX_FILES_PER_BATCH:
        logger.warning(
            "batch_validation_failed",
            error="too_many_files",
            file_count=file_count,
            max_allowed=MAX_FILES_PER_BATCH,
        )
        raise BatchValidationError(
            code="TOO_MANY_FILES",
            message=f"Batch contains {file_count} files, maximum allowed is {MAX_FILES_PER_BATCH}",
        )

    logger.debug(
        "batch_file_count_validated",
        file_count=file_count,
        max_allowed=MAX_FILES_PER_BATCH,
    )


async def validate_batch_total_size(files: list[UploadFile]) -> int:
    """Validate total batch size and return the total.

    Reads each file to determine size, validates against maximum batch size,
    and returns total size for use in logging/monitoring. Files are reset
    after reading so subsequent operations can read them again.

    Args:
        files: List of uploaded files to validate.

    Returns:
        Total size of all files in bytes.

    Raises:
        BatchValidationError: If total size exceeds MAX_BATCH_SIZE_BYTES (500MB).
    """
    total_size = 0
    file_sizes = []

    # Read each file to determine size
    for file in files:
        content = await file.read()
        file_size = len(content)
        total_size += file_size
        file_sizes.append((file.filename, file_size))
        # Reset file pointer for subsequent reads
        await file.seek(0)

    if total_size > MAX_BATCH_SIZE_BYTES:
        logger.warning(
            "batch_validation_failed",
            error="batch_too_large",
            total_size_bytes=total_size,
            total_size_mb=total_size / (1024 * 1024),
            max_size_mb=MAX_BATCH_SIZE_MB,
            file_count=len(files),
        )
        raise BatchValidationError(
            code="BATCH_TOO_LARGE",
            message=f"Total batch size {total_size / (1024 * 1024):.2f}MB exceeds maximum allowed size of {MAX_BATCH_SIZE_MB}MB",
        )

    logger.debug(
        "batch_total_size_validated",
        total_size_bytes=total_size,
        total_size_mb=total_size / (1024 * 1024),
        file_count=len(files),
        max_size_mb=MAX_BATCH_SIZE_MB,
    )

    return total_size


async def validate_batch(files: list[UploadFile]) -> int:
    """Orchestrate all batch-level validations.

    Validates file count and total size constraints for the batch upload.

    Args:
        files: List of uploaded files to validate.

    Returns:
        Total size of all files in bytes.

    Raises:
        BatchValidationError: If any batch-level validation fails.
    """
    logger.info("batch_validation_started", file_count=len(files))

    # Validate file count first (cheapest check)
    await validate_batch_file_count(files)

    # Validate total size
    total_size = await validate_batch_total_size(files)

    logger.info(
        "batch_validation_completed",
        file_count=len(files),
        total_size_bytes=total_size,
    )

    return total_size
