"""
pdf_processor.py - Converts an uploaded PDF drawing set into page images.

Each page becomes a base64-encoded JPEG that the vision model can read.
Higher DPI = better accuracy but slower/heavier requests. Adapted from the
IronBid pipeline (AI_Takeoffs); behavior is intentionally identical so the
two projects stay comparable.
"""

import base64
from io import BytesIO
from typing import List, Dict

from pdf2image import convert_from_path
from PIL import Image

from backend import config


def convert_pdf_to_images(pdf_path: str) -> List[Dict]:
    """
    Convert each page of a PDF into a base64-encoded JPEG.

    Returns a list of dicts:
      { "page_number": int, "base64": str, "width": int, "height": int }
    """
    print(f"[PDF] Converting {pdf_path} at {config.PDF_DPI} DPI...")

    pages = convert_from_path(
        pdf_path,
        dpi=config.PDF_DPI,
        fmt="jpeg",
        thread_count=4,
        use_pdftocairo=True,
    )

    results: List[Dict] = []
    total = min(len(pages), config.MAX_PAGES)

    for i, page in enumerate(pages[:total]):
        # 2400px gives ~100px/inch on a 24x36 sheet, the minimum needed to
        # read 8pt room annotations and dimension strings.
        page = _resize_if_needed(page, max_dimension=config.MAX_DIMENSION)

        buffer = BytesIO()
        page.save(buffer, format="JPEG", quality=85)
        b64 = base64.b64encode(buffer.getvalue()).decode("utf-8")

        results.append({
            "page_number": i + 1,
            "base64": b64,
            "width": page.width,
            "height": page.height,
        })
        print(f"[PDF] Page {i+1}/{total} encoded ({page.width}x{page.height})")

    print(f"[PDF] Done - {len(results)} pages ready for analysis")
    return results


def render_page_jpeg(pdf_path: str, page: int, dpi: int = 150,
                     max_dimension: int = 3000) -> bytes:
    """
    Render a single 1-based page of a PDF to JPEG bytes, for the sheet viewer.

    Higher DPI than the analysis pass (default 150) so text is legible on
    screen. Raises IndexError if the page is out of range.
    """
    if page < 1:
        raise IndexError(f"page {page} out of range")
    pages = convert_from_path(pdf_path, dpi=dpi, fmt="jpeg",
                              first_page=page, last_page=page, use_pdftocairo=True)
    if not pages:
        raise IndexError(f"page {page} out of range")
    img = _resize_if_needed(pages[0], max_dimension=max_dimension)
    buffer = BytesIO()
    img.save(buffer, format="JPEG", quality=85)
    return buffer.getvalue()


def _resize_if_needed(image: Image.Image, max_dimension: int = 2400) -> Image.Image:
    """Resize image proportionally if either dimension exceeds max_dimension."""
    w, h = image.size
    if w <= max_dimension and h <= max_dimension:
        return image
    ratio = min(max_dimension / w, max_dimension / h)
    new_size = (int(w * ratio), int(h * ratio))
    return image.resize(new_size, Image.LANCZOS)
