"""Storage de archivos detrás de una interfaz simple.

Hoy: disco local (dev). Mañana: se agrega R2Storage con la misma interfaz `save`/`delete` y se cambia
la instancia `storage` de abajo — sin tocar las rutas. Por eso el upload no conoce el proveedor.
"""
import os
import secrets
from abc import ABC, abstractmethod

from app.core.config import settings

# Tipos de imagen permitidos → extensión en disco
ALLOWED_IMAGE_TYPES = {
    "image/jpeg": ".jpg",
    "image/png": ".png",
    "image/webp": ".webp",
}
MAX_IMAGE_BYTES = 5 * 1024 * 1024  # 5 MB


class Storage(ABC):
    @abstractmethod
    def save(self, data: bytes, ext: str) -> str:
        """Guarda los bytes y devuelve la URL pública."""

    @abstractmethod
    def delete(self, url: str) -> None:
        """Borra el archivo referido por la URL pública (si existe)."""


class LocalDiskStorage(Storage):
    """Guarda en `MEDIA_DIR` y sirve bajo `PUBLIC_MEDIA_URL` (montado en /media)."""

    def __init__(self) -> None:
        self.dir = settings.MEDIA_DIR
        self.base = settings.PUBLIC_MEDIA_URL.rstrip("/")
        os.makedirs(self.dir, exist_ok=True)

    def save(self, data: bytes, ext: str) -> str:
        name = f"{secrets.token_hex(16)}{ext}"
        with open(os.path.join(self.dir, name), "wb") as f:
            f.write(data)
        return f"{self.base}/{name}"

    def delete(self, url: str) -> None:
        name = url.rsplit("/", 1)[-1]
        path = os.path.join(self.dir, name)
        if os.path.isfile(path):
            os.remove(path)


# Instancia global — cambiar acá para pasar a R2 en producción.
storage: Storage = LocalDiskStorage()
