Framework for embedding localizations into Rust types
//! Implementations of `Localize` for various layout helpers

use icu_locale::Locale;

use crate::list::Length;
use crate::macros::impl_serialize;
use crate::{Context, Localize};

#[derive(Debug, Clone)]
pub struct Lines<L: Localize, const SEPARATOR_COUNT: usize = 1> {
    messages: Vec<L>,
}

impl_serialize!(Lines, messages);

impl<L: Localize, const SEPARATOR_COUNT: usize> Lines<L, SEPARATOR_COUNT> {
    #[must_use]
    pub const fn new(messages: Vec<L>) -> Self {
        Self { messages }
    }
}

impl<L: Localize, const SEPARATOR_COUNT: usize> Length for Lines<L, SEPARATOR_COUNT> {
    fn len(&self) -> usize {
        self.messages.len()
    }
}

impl<L: Localize, const SEPARATOR_COUNT: usize> Localize for Lines<L, SEPARATOR_COUNT> {
    fn localize(&self, context: &Context, buffer: &mut String) {
        let separator = "\n".repeat(SEPARATOR_COUNT);

        for (index, message) in self.messages.iter().enumerate() {
            // Add the newlines before every additional line
            if index > 0 {
                buffer.push_str(&separator);
            }

            message.localize(context, buffer);
        }
    }
}

#[derive(Debug, Clone)]
pub struct Padded<L: Localize, const VERTICAL_PADDING: usize, const HORIZONTAL_PADDING: usize> {
    message: L,
}

impl_serialize!(Padded, message, VERTICAL_PADDING: usize, HORIZONTAL_PADDING: usize);

impl<L: Localize, const VERTICAL_PADDING: usize, const HORIZONTAL_PADDING: usize>
    Padded<L, VERTICAL_PADDING, HORIZONTAL_PADDING>
{
    pub const fn new(message: L) -> Self {
        Self { message }
    }
}

impl<L: Localize, const VERTICAL_PADDING: usize, const HORIZONTAL_PADDING: usize> Localize
    for Padded<L, VERTICAL_PADDING, HORIZONTAL_PADDING>
{
    fn canonical_locale(&self) -> Locale {
        self.message.canonical_locale()
    }

    fn available_locales(&self) -> Vec<Locale> {
        self.message.available_locales()
    }

    fn localize(&self, context: &Context, buffer: &mut String) {
        let mut localized_message = String::new();
        self.message.localize(context, &mut localized_message);

        let vertical_padding = "\n".repeat(VERTICAL_PADDING);
        let horizontal_padding = " ".repeat(HORIZONTAL_PADDING);

        // Only apply the vertical padding above the message, not below
        buffer.push_str(&vertical_padding);

        // Apply the horizontal padding to each line
        for (index, line) in localized_message.lines().enumerate() {
            // Add a newline before every additional line
            if index > 0 {
                buffer.push('\n');
            }

            buffer.push_str(&horizontal_padding);
            buffer.push_str(line);
        }
    }
}