Framework for embedding localizations into Rust types
use crate::macros::impl_serialize;
use crate::{Context, Localize};

use anstyle::{AnsiColor, Color, Style};

macro_rules! style_attribute {
    ($function_name:ident) => {
        #[must_use]
        pub const fn $function_name(mut self) -> Self {
            self.style = self.style.$function_name();

            self
        }
    };
}

#[derive(Debug, Clone)]
pub struct Styled<L: Localize> {
    message: L,
    style: Style,
}

impl_serialize!(Styled, message);

impl<L: Localize> Localize for Styled<L> {
    fn localize(&self, context: &Context, buffer: &mut String) {
        // Prefix with the terminal color codes
        if context.use_colors {
            let prefix = self.style.render().to_string();
            buffer.push_str(&prefix);
        }

        self.message.localize(context, buffer);

        // Suffix with the terminal reset codes
        if context.use_colors {
            let suffix = self.style.render_reset().to_string();
            buffer.push_str(&suffix);
        }
    }
}

impl<L: Localize> Styled<L> {
    pub const fn new(message: L) -> Self {
        Self {
            message,
            style: Style::new(),
        }
    }

    style_attribute!(bold);
    style_attribute!(dimmed);
    style_attribute!(italic);
    style_attribute!(strikethrough);

    #[must_use]
    pub const fn color(mut self, ansi_color: AnsiColor) -> Self {
        self.style = self.style.fg_color(Some(Color::Ansi(ansi_color)));

        self
    }
}