"""File upload service — handles image uploads, validation, and thumbnail generation."""

import os
import uuid as _uuid
from pathlib import Path

from fastapi import UploadFile
from PIL import Image

ALLOWED_EXTENSIONS = {".jpg", ".jpeg", ".png", ".webp", ".bmp", ".tiff"}
MAX_IMAGE_SIZE = 50 * 1024 * 1024  # 50 MB
THUMBNAIL_SIZE = (800, 400)
ASPECT_RATIO_TOLERANCE = 0.05


async def save_upload(
    file: UploadFile,
    upload_dir: str = "uploads/images",
) -> dict[str, str]:
    """Save an uploaded file, validate aspect ratio, generate thumbnail.

    Returns:
        dict with ``image_url`` and ``thumbnail_url`` (relative paths).

    Raises:
        ValueError: if the file is invalid or processing fails.
    """
    # ── Validate file extension ──────────────────────────────────────── #
    ext = os.path.splitext(file.filename or "image.jpg")[1].lower()
    if ext not in ALLOWED_EXTENSIONS:
        raise ValueError(f"不支持的文件格式: {ext}")

    # ── Read file content ────────────────────────────────────────────── #
    content = await file.read()
    if len(content) > MAX_IMAGE_SIZE:
        raise ValueError("文件大小超过限制 (50MB)")

    # ── Create upload directory ───────────────────────────────────────── #
    upload_path = Path(upload_dir)
    upload_path.mkdir(parents=True, exist_ok=True)

    # ── Save original file ───────────────────────────────────────────── #
    filename = f"{_uuid.uuid4().hex}{ext}"
    filepath = upload_path / filename
    with open(filepath, "wb") as f:
        f.write(content)

    try:
        img = Image.open(filepath)
        width, height = img.size

        # ── Validate 2:1 aspect ratio (with tolerance) ───────────────── #
        if height > 0:
            ratio = width / height
        else:
            ratio = 0.0

        if abs(ratio - 2.0) > ASPECT_RATIO_TOLERANCE:
            os.remove(filepath)
            raise ValueError(f"图片宽高比必须为 2:1，当前为 {ratio:.2f}:1")

        # ── Generate thumbnail ───────────────────────────────────────── #
        thumb_filename = f"{_uuid.uuid4().hex}_thumb{ext}"
        thumb_path = upload_path / thumb_filename

        # Resize maintaining aspect ratio, then centre-crop to 800x400
        img.thumbnail(THUMBNAIL_SIZE, Image.Resampling.LANCZOS)
        thumb = Image.new("RGB", THUMBNAIL_SIZE, (0, 0, 0))
        offset_x = (THUMBNAIL_SIZE[0] - img.width) // 2
        offset_y = (THUMBNAIL_SIZE[1] - img.height) // 2
        thumb.paste(img, (offset_x, offset_y))
        thumb.save(thumb_path, quality=85)

        image_url = f"/uploads/images/{filename}"
        thumbnail_url = f"/uploads/images/{thumb_filename}"

        return {
            "image_url": image_url,
            "thumbnail_url": thumbnail_url,
        }

    except (IOError, OSError) as e:
        # Clean up on error
        if filepath.exists():
            os.remove(filepath)
        raise ValueError(f"图片处理失败: {str(e)}")
