"""PDF → images PNG 300 dpi avec cache par hash SHA256.

Applique optionnellement un deskew automatique (redressement) sur chaque page
pour corriger le biais d'inclinaison des scans. Voir pipeline/deskew.py.
"""
import hashlib
import os
from pathlib import Path
from pdf2image import convert_from_path
from PIL import Image

from .deskew import deskew_image, MIN_ANGLE_DEG

DEFAULT_DPI = 300
CACHE_ROOT = Path(".cache/images")


def pdf_hash(pdf_path: str) -> str:
    """Hash SHA256 court du contenu PDF."""
    h = hashlib.sha256()
    with open(pdf_path, "rb") as f:
        for chunk in iter(lambda: f.read(65536), b""):
            h.update(chunk)
    return h.hexdigest()[:16]


def pdf_to_images(pdf_path: str, dpi: int = DEFAULT_DPI,
                   cache_root: Path = CACHE_ROOT,
                   deskew: bool = True) -> list[Path]:
    """Convertit un PDF en PNG 300 dpi. Retourne la liste des chemins (1 par page).

    Le cache est indexé par hash du PDF : un PDF inchangé n'est jamais reconverti.

    Avec `deskew=True` (défaut), chaque page est redressée si son angle de skew
    dépasse le seuil défini dans `pipeline.deskew.MIN_ANGLE_DEG` (0.3°). L'angle
    appliqué est persisté dans un fichier `<page>.skew` à côté (pour audit).
    """
    cache_root = Path(cache_root)
    h = pdf_hash(pdf_path)
    out_dir = cache_root / h
    out_dir.mkdir(parents=True, exist_ok=True)

    # Le glob est strict pour ne pas attraper les crops intermédiaires
    # (page_XX_recodage.png, etc.)
    existing = sorted(p for p in out_dir.glob("page_*.png")
                      if p.stem.replace("page_", "").isdigit())
    if existing:
        return existing

    pages = convert_from_path(pdf_path, dpi)
    paths = []
    for i, img in enumerate(pages, 1):
        if deskew:
            img, applied = deskew_image(img)
            if applied != 0.0:
                # Trace d'audit : on note l'angle corrigé
                (out_dir / f"page_{i:02d}.skew").write_text(f"{applied:.3f}\n")
        p = out_dir / f"page_{i:02d}.png"
        img.save(p, "PNG", optimize=True)
        paths.append(p)
    return paths


def load_image(path: Path) -> Image.Image:
    return Image.open(path)
