use pagetop::prelude::*;

// **< Size >***************************************************************************************

/// Define las **dimensiones** de una imagen ([`Image`](crate::theme::bs::Image)).
#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)]
pub enum Size {
    /// Ajuste automático por defecto.
    ///
    /// La imagen usa su tamaño natural o se ajusta al contenedor donde se publica.
    #[default]
    Auto,
    /// Establece explícitamente el **ancho y alto** de la imagen.
    ///
    /// Útil cuando se desea fijar ambas dimensiones de forma exacta. Ten en cuenta que la imagen
    /// puede distorsionarse si no se mantiene la proporción original.
    Dimensions(UnitValue, UnitValue),
    /// Establece sólo el **ancho** de la imagen.
    ///
    /// La altura se ajusta proporcionalmente de manera automática.
    Width(UnitValue),
    /// Establece sólo la **altura** de la imagen.
    ///
    /// El ancho se ajusta proporcionalmente de manera automática.
    Height(UnitValue),
    /// Establece **el mismo valor** para el ancho y el alto de la imagen.
    ///
    /// Práctico para forzar rápidamente un área cuadrada. Ten en cuenta que la imagen puede
    /// distorsionarse si la original no es cuadrada.
    Both(UnitValue),
}

impl Size {
    /// Devuelve el valor del atributo `style` en función del tamaño, o `None` si no aplica.
    #[inline]
    pub fn to_style(self) -> Option<String> {
        match self {
            Self::Auto => None,
            Self::Dimensions(w, h) => Some(format!("width: {w}; height: {h};")),
            Self::Width(w) => Some(format!("width: {w};")),
            Self::Height(h) => Some(format!("height: {h};")),
            Self::Both(v) => Some(format!("width: {v}; height: {v};")),
        }
    }
}

// **< Source >*************************************************************************************

/// Especifica la **fuente** para publicar una imagen ([`Image`](crate::theme::bs::Image)).
#[derive(AutoDefault, Clone, Debug, PartialEq)]
pub enum Source {
    /// Imagen con el logotipo de PageTop.
    #[default]
    Logo(PageTopSvg),
    /// Imagen que se adapta automáticamente a su contenedor.
    ///
    /// Lleva asociada la URL (o ruta) de la imagen.
    Responsive(CowStr),
    /// Imagen que aplica el estilo **miniatura** de Bootstrap.
    ///
    /// Lleva asociada la URL (o ruta) de la imagen.
    Thumbnail(CowStr),
    /// Imagen sin clases específicas de Bootstrap, útil para controlar con CSS propio.
    ///
    /// Lleva asociada la URL (o ruta) de la imagen.
    Plain(CowStr),
}

impl Source {
    const IMG_FLUID: &str = "img-fluid";
    const IMG_THUMBNAIL: &str = "img-thumbnail";

    /// Imagen con el logotipo de PageTop.
    #[inline]
    pub fn logo(svg: PageTopSvg) -> Self {
        Self::Logo(svg)
    }

    /// Imagen responsive (`img-fluid`).
    #[inline]
    pub fn responsive(url: impl Into<CowStr>) -> Self {
        Self::Responsive(url.into())
    }

    /// Imagen miniatura (`img-thumbnail`).
    #[inline]
    pub fn thumbnail(url: impl Into<CowStr>) -> Self {
        Self::Thumbnail(url.into())
    }

    /// Imagen sin clases adicionales.
    #[inline]
    pub fn plain(url: impl Into<CowStr>) -> Self {
        Self::Plain(url.into())
    }

    /// Devuelve la clase base asociada a la imagen según la fuente.
    #[inline]
    pub const fn as_str(&self) -> &'static str {
        match self {
            Source::Logo(_) | Source::Responsive(_) => Self::IMG_FLUID,
            Source::Thumbnail(_) => Self::IMG_THUMBNAIL,
            Source::Plain(_) => "",
        }
    }

    /// Añade la clase asociada al tipo de imagen a la cadena de clases.
    #[inline]
    pub fn push_to(&self, classes: &mut String) {
        let s = self.as_str();
        if s.is_empty() {
            return;
        }
        if !classes.is_empty() {
            classes.push(' ');
        }
        classes.push_str(s);
    }

    /// Devuelve la clase asociada al tipo de imagen.
    pub fn to_class(&self) -> String {
        let mut class = String::new();
        self.push_to(&mut class);
        class
    }
}
