"""
Thumbnail generation for uploaded media files.

Supports:
  - Images (via Pillow): JPEG thumbnail at 300×300 max
  - Videos (via ffmpeg subprocess): extract first frame as JPEG
  - PDFs (via pdf2image + Poppler): render first page as JPEG

Returns None if the type is unsupported or if generation fails.
"""
import io
import logging
import subprocess
from pathlib import Path

logger = logging.getLogger(__name__)

THUMB_SIZE = (220, 220)  # small enough for gallery tiles; keeps files ~4-6 KB


def _thumb_from_image(content: bytes) -> bytes | None:
    try:
        from PIL import Image, ImageOps
        img = Image.open(io.BytesIO(content))
        img = ImageOps.exif_transpose(img)  # honour EXIF Orientation tag before resizing
        img = img.convert("RGB")
        img.thumbnail(THUMB_SIZE, Image.LANCZOS)
        out = io.BytesIO()
        # quality=55 + optimize=True + progressive encoding → ~4-6 KB for typical photos
        img.save(out, format="JPEG", quality=65, optimize=True, progressive=True)
        return out.getvalue()
    except Exception as e:
        logger.warning("Image thumbnail failed: %s", e)
        return None


def _thumb_from_video(content: bytes) -> bytes | None:
    """
    Extract the first frame of a video as a JPEG thumbnail.

    We write the video to a temp file instead of piping it to ffmpeg because
    most video containers (MP4, MOV, MKV …) store their index (moov atom) at
    an arbitrary offset and ffmpeg cannot seek on a pipe — causing rc≠0 with
    "moov atom not found" or similar errors when stdin is used.
    """
    import tempfile
    import os
    try:
        # Write to a temp file so ffmpeg can seek freely
        with tempfile.NamedTemporaryFile(suffix=".video", delete=False) as tmp_in:
            tmp_in.write(content)
            tmp_in_path = tmp_in.name

        with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as tmp_out:
            tmp_out_path = tmp_out.name

        try:
            result = subprocess.run(
                [
                    "ffmpeg", "-y",
                    "-i", tmp_in_path,
                    "-vframes", "1",
                    "-vf", f"scale={THUMB_SIZE[0]}:-2",
                    "-q:v", "4",   # JPEG quality 1-31 (lower = better); 4 ≈ ~80% quality
                    tmp_out_path,
                ],
                capture_output=True,
                timeout=60,
            )
            if result.returncode == 0 and os.path.getsize(tmp_out_path) > 0:
                with open(tmp_out_path, "rb") as f:
                    return f.read()
            logger.warning(
                "ffmpeg video thumb failed (rc=%s): %s",
                result.returncode,
                result.stderr[-400:].decode(errors="replace") if result.stderr else "",
            )
            return None
        finally:
            os.unlink(tmp_in_path)
            try:
                os.unlink(tmp_out_path)
            except FileNotFoundError:
                pass
    except FileNotFoundError:
        logger.warning("ffmpeg not found — video thumbnails unavailable")
        return None
    except Exception as e:
        logger.warning("Video thumbnail failed: %s", e)
        return None


def _thumb_from_pdf(content: bytes) -> bytes | None:
    try:
        from pdf2image import convert_from_bytes
        pages = convert_from_bytes(content, first_page=1, last_page=1, size=THUMB_SIZE)
        if not pages:
            return None
        out = io.BytesIO()
        pages[0].save(out, format="JPEG", quality=55, optimize=True, progressive=True)
        return out.getvalue()
    except ImportError:
        logger.warning("pdf2image not installed — PDF thumbnails unavailable")
        return None
    except Exception as e:
        logger.warning("PDF thumbnail failed: %s", e)
        return None


def generate_thumbnail(content: bytes, mime_type: str, filename: str) -> bytes | None:
    """
    Generate a small JPEG thumbnail for the given file content.
    Returns JPEG bytes or None if unsupported / generation fails.
    """
    mt = (mime_type or "").lower()
    fn = (filename or "").lower()

    if mt.startswith("image/"):
        return _thumb_from_image(content)
    if mt.startswith("video/"):
        return _thumb_from_video(content)
    if mt == "application/pdf" or fn.endswith(".pdf"):
        return _thumb_from_pdf(content)

    return None
