"""
Pydantic schemas for PDF MCP server tool inputs and outputs
"""
from pydantic import BaseModel, Field, field_validator
from typing import List, Optional, Literal
from .config import config


# ============================================================================
# list_pdfs tool schemas
# ============================================================================

class ListPDFsInput(BaseModel):
    """Input schema for list_pdfs tool"""
    working_directory: Optional[str] = Field(
        default=".",
        description="Working directory to search for PDFs (relative or absolute)"
    )
    include_subdirectories: bool = Field(
        default=True,
        description="Include subdirectories in search"
    )
    max_depth: Optional[int] = Field(
        default_factory=lambda: config.max_recursion_depth,
        description="Maximum recursion depth (None = unlimited)"
    )


class PDFInfo(BaseModel):
    """Metadata for a single PDF file"""
    name: str = Field(description="File name with extension")
    path: str = Field(description="Absolute file path for use with read_pdf")
    pages: int = Field(description="Total number of pages")
    size_bytes: int = Field(description="File size in bytes")


class ListPDFsOutput(BaseModel):
    """Output schema for list_pdfs tool"""
    pdfs: List[PDFInfo] = Field(description="List of PDF files found")
    total_count: int = Field(description="Total number of PDFs found")
    working_directory: str = Field(description="Working directory that was searched")


class ListPDFsError(BaseModel):
    """Error response for list_pdfs tool"""
    error: Literal[
        "DIRECTORY_NOT_FOUND",
        "NOT_A_DIRECTORY",
        "PERMISSION_DENIED",
        "INTERNAL_ERROR"
    ] = Field(description="Error type")
    message: str = Field(description="Human-readable error message")


# ============================================================================
# read_pdf tool schemas
# ============================================================================

class ReadPDFInput(BaseModel):
    """Input schema for read_pdf tool"""
    file_path: str = Field(
        ...,
        description="Path to PDF file (relative to working directory or absolute)"
    )
    start_page: int = Field(
        default=1,
        ge=1,
        description="Start page number (1-indexed, inclusive)"
    )
    end_page: Optional[int] = Field(
        default=None,
        ge=1,
        description="End page number (1-indexed, inclusive). None = last page"
    )
    filter_header_footer: bool = Field(
        default=True,
        description="Filter out header/footer images based on size and position"
    )
    crop_images: bool = Field(
        default=True,
        description="Crop images to maximum dimension (A4 1/4 resolution)"
    )
    max_image_dimension: int = Field(
        default_factory=lambda: config.max_image_dimension,
        ge=28,
        le=4096,
        description="Maximum image dimension in pixels (28-4096)"
    )
    extraction_mode: str = Field(
        default="auto",
        description=(
            "Content extraction mode:\n"
            "- 'auto': Smart detection - extract text/tables/images, add page image only if corrupted (default)\n"
            "- 'text_only': Extract text/tables only, never add page image\n"
            "- 'image_only': Skip text extraction, provide only full page images (for scanned PDFs)"
        )
    )
    page_image_dpi: int = Field(
        default_factory=lambda: config.page_image_dpi,
        ge=50,
        le=300,
        description="DPI for page image rendering (50-300, default: 100)"
    )

    @field_validator('extraction_mode')
    @classmethod
    def validate_extraction_mode(cls, v):
        """Validate extraction mode"""
        valid_modes = ['auto', 'text_only', 'image_only']
        if v not in valid_modes:
            raise ValueError(f"extraction_mode must be one of {valid_modes}")
        return v

    @field_validator('end_page')
    @classmethod
    def validate_end_page(cls, v, info):
        """Validate end_page is >= start_page"""
        if v is not None and 'start_page' in info.data:
            if v < info.data['start_page']:
                raise ValueError("end_page must be >= start_page")
        return v


class ContentBlock(BaseModel):
    """Single content block (text, table, or image)"""
    type: Literal["text", "table", "image"] = Field(description="Content type: 'text', 'table', or 'image'")
    content: Optional[str] = Field(default=None, description="Text content, table markdown, or base64 image")


class PageData(BaseModel):
    """Data for a single PDF page"""
    page_number: int = Field(description="Page number (1-indexed)")
    content_blocks: List[ContentBlock] = Field(
        description="Ordered list of content blocks (text/table/image in reading order)"
    )
    text_corrupted: Optional[bool] = Field(
        default=None,
        description="Whether text is corrupted (auto-detected)"
    )
    corruption_ratio: Optional[float] = Field(
        default=None,
        description="Text corruption ratio (0.0-1.0)"
    )
    page_image: Optional[str] = Field(
        default=None,
        description="Full page as image (base64) if text corrupted or requested"
    )
    page_image_width: Optional[int] = Field(default=None, description="Page image width")
    page_image_height: Optional[int] = Field(default=None, description="Page image height")
    extractable_char_count: Optional[int] = Field(
        default=None,
        description="Number of extractable text characters (only in image_only mode)"
    )
    text_hint: Optional[str] = Field(
        default=None,
        description="Hint about text extraction availability (only in image_only mode)"
    )


class SuggestedRange(BaseModel):
    """Suggested page range that respects limits"""
    start_page: int = Field(description="Suggested start page")
    end_page: int = Field(description="Suggested end page")
    estimated_images: int = Field(description="Estimated number of images in range")
    page_count: int = Field(description="Number of pages in range")


class ReadPDFSuccess(BaseModel):
    """Successful read_pdf response"""
    file_path: str = Field(description="Path to the PDF file that was read")
    pages: List[PageData] = Field(description="List of page data in order")
    total_pages_read: int = Field(description="Total number of pages read")
    total_images: int = Field(description="Total number of images extracted")


class ReadPDFError(BaseModel):
    """Error response for read_pdf tool"""
    error: Literal[
        "PAGE_LIMIT_EXCEEDED",
        "IMAGE_LIMIT_EXCEEDED",
        "FILE_NOT_FOUND",
        "INVALID_PDF",
        "INVALID_PAGE_RANGE",
        "PERMISSION_DENIED"
    ] = Field(description="Error type")
    message: str = Field(description="Human-readable error message")
    total_pages: Optional[int] = Field(
        default=None,
        description="Total pages in document (if applicable)"
    )
    total_images: Optional[int] = Field(
        default=None,
        description="Total images in requested range (if applicable)"
    )
    suggested_ranges: Optional[List[SuggestedRange]] = Field(
        default=None,
        description="Suggested page ranges to read instead"
    )
    suggested_files: Optional[List[str]] = Field(
        default=None,
        description="Similar PDF filenames (when file not found)"
    )


# ============================================================================
# Validation result (internal)
# ============================================================================

class ValidationResult(BaseModel):
    """Internal validation result"""
    valid: bool
    error: Optional[str] = None
    message: Optional[str] = None
    total_pages: Optional[int] = None
    total_images: Optional[int] = None
    suggested_ranges: Optional[List[SuggestedRange]] = None