"""Utilitas berkas gambar: validasi isi, normalisasi ukuran, dan proxy.

Aturan yang dipegang modul ini:
  * ekstensi diperiksa dari daftar putih, nama simpanan selalu UUID;
  * isi berkas divalidasi Pillow (bukan hanya ekstensinya);
  * foto besar dinormalkan ke maksimum MASK_LONG_EDGE supaya penampil tetap
    ringan di ponsel;
  * proxy MASK_PROXY dibuat untuk tampilan awal, foto penuh dimuat belakangan.
"""

from __future__ import annotations

import os
import uuid
from pathlib import Path

from PIL import Image, UnidentifiedImageError

EKSTENSI_BOLEH = {"png", "jpg", "jpeg", "webp", "gif"}
MASK_LONG_EDGE = 8000
MASK_PROXY = 1600
KUALITAS_PENUH = 88
KUALITAS_PROXY = 82


class BerkasTidakSah(ValueError):
    """Berkas unggahan bukan gambar yang didukung."""


def _ekstensi(nama: str) -> str:
    nama = (nama or "").strip()
    if "." not in nama:
        raise BerkasTidakSah("Berkas tanpa ekstensi tidak dikenali.")
    ext = nama.rsplit(".", 1)[-1].lower()
    if ext not in EKSTENSI_BOLEH:
        raise BerkasTidakSah(
            f"Format .{ext or '?'} tidak didukung "
            f"({', '.join(sorted(EKSTENSI_BOLEH))}).")
    return "jpg" if ext == "jpeg" else ext


def _buka(jalur: Path) -> tuple[Image.Image, str]:
    """Buka dan verifikasi isi berkas; kembalikan gambar (sudah dibuka ulang)."""
    try:
        with Image.open(jalur) as uji:
            uji.verify()
        gambar = Image.open(jalur)
        gambar.load()
    except (UnidentifiedImageError, OSError, ValueError) as exc:
        raise BerkasTidakSah(
            "Isi berkas bukan gambar yang bisa dibaca (coba simpan ulang sebagai JPG/PNG)."
        ) from exc
    return gambar, (gambar.format or "").upper()


def _simpan(gambar: Image.Image, jalur: Path, ext: str) -> None:
    if ext == "png":
        if gambar.mode not in ("RGB", "RGBA", "L", "LA"):
            gambar = gambar.convert("RGBA")
        gambar.save(jalur, "PNG", optimize=True)
    else:
        if gambar.mode != "RGB":
            latar = Image.new("RGB", gambar.size, (255, 255, 255))
            if gambar.mode in ("RGBA", "LA", "P"):
                gambar = gambar.convert("RGBA")
                latar.paste(gambar, mask=gambar.split()[-1])
            else:
                latar.paste(gambar.convert("RGB"))
            gambar = latar
        gambar.save(jalur, "JPEG", quality=KUALITAS_PENUH, optimize=True)


def simpan_unggahan(berkas, folder: Path) -> dict:
    """Simpan unggahan ke ``folder``; kembalikan nama, proxy, dan dimensi.

    Raises:
        BerkasTidakSah: ekstensi tak didukung atau isi bukan gambar.
    """
    folder = Path(folder)
    folder.mkdir(parents=True, exist_ok=True)
    ext = _ekstensi(berkas.filename)

    dasar = uuid.uuid4().hex
    nama = f"{dasar}.{ext}"
    tujuan = folder / nama
    sementara = folder / f".{dasar}.tmp"

    berkas.save(sementara)
    try:
        gambar, _format = _buka(sementara)
        lebar, tinggi = gambar.size

        if max(lebar, tinggi) > MASK_LONG_EDGE:
            gambar.thumbnail((MASK_LONG_EDGE, MASK_LONG_EDGE), Image.LANCZOS)
            lebar, tinggi = gambar.size
            _simpan(gambar, tujuan, ext)
            sementara.unlink(missing_ok=True)
        else:
            os.replace(sementara, tujuan)  # bytes asli dipertahankan

        proxy = None
        if max(lebar, tinggi) > MASK_PROXY:
            gambar.thumbnail((MASK_PROXY, MASK_PROXY), Image.LANCZOS)
            proxy_nama = f"{dasar}_proxy.jpg"
            if gambar.mode != "RGB":
                gambar = gambar.convert("RGB")
            gambar.save(folder / proxy_nama, "JPEG", quality=KUALITAS_PROXY, optimize=True)
            proxy = proxy_nama

        return {"nama": nama, "proxy": proxy, "lebar": lebar, "tinggi": tinggi}
    except Exception:
        sementara.unlink(missing_ok=True)
        tujuan.unlink(missing_ok=True)
        raise
