from __future__ import annotations

from io import BytesIO
from uuid import uuid4

from PIL import Image

from app.core.config import settings
from app.core.storage import upload_object

ALLOWED_MIME = {
    "image/jpeg": ".jpg",
    "image/png": ".png",
    "image/webp": ".webp",
}

FORMAT_TO_MIME = {
    "JPEG": "image/jpeg",
    "PNG": "image/png",
    "WEBP": "image/webp",
}


class AvatarValidationError(ValueError):
    pass


def validate_and_process_avatar(content: bytes) -> tuple[str, bytes]:
    if len(content) > settings.avatar_max_bytes:
        raise AvatarValidationError("FILE_TOO_LARGE")
    if not content:
        raise AvatarValidationError("INVALID_IMAGE")

    try:
        with Image.open(BytesIO(content)) as image:
            image.verify()
        with Image.open(BytesIO(content)) as image:
            mime = FORMAT_TO_MIME.get(image.format or "")
            if mime not in ALLOWED_MIME:
                raise AvatarValidationError("INVALID_MIME")

            buffer = BytesIO()
            if mime == "image/jpeg":
                rgb = image.convert("RGB")
                rgb.save(buffer, format="JPEG", quality=85, optimize=True)
            elif mime == "image/png":
                image.save(buffer, format="PNG", optimize=True)
            else:
                image.save(buffer, format="WEBP", quality=85, method=6)
            return mime, buffer.getvalue()
    except AvatarValidationError:
        raise
    except Exception as exc:
        raise AvatarValidationError("INVALID_IMAGE") from exc


def upload_user_avatar(user_id: str, content: bytes) -> str:
    mime, processed = validate_and_process_avatar(content)
    extension = ALLOWED_MIME[mime]
    key = f"avatars/{user_id}/{uuid4()}{extension}"
    upload_object(key, processed, mime)
    return f"/api/v1/media/files/{key}"
