use std::sync::Arc;

use gpui::Hsla;
use serde::Deserialize;

use crate::{
    amber, blue, cyan, gold, grass, indigo, iris, jade, lime, orange, pink, purple, tomato,
    try_parse_color,
};

/// A collection of colors that are used to color indent aware lines in the editor.
#[derive(Clone, Debug, Deserialize, PartialEq)]
pub struct AccentColors(pub Arc<[Hsla]>);

impl Default for AccentColors {
    /// Don't use this!
    /// We have to have a default to be `[refineable::Refinable]`.
    /// TODO "Find a way to not need this for Refinable"
    fn default() -> Self {
        Self::dark()
    }
}

impl AccentColors {
    /// Returns the set of dark accent colors.
    pub fn dark() -> Self {
        Self(Arc::from(vec![
            blue().dark().step_9(),
            orange().dark().step_9(),
            pink().dark().step_9(),
            lime().dark().step_9(),
            purple().dark().step_9(),
            amber().dark().step_9(),
            jade().dark().step_9(),
            tomato().dark().step_9(),
            cyan().dark().step_9(),
            gold().dark().step_9(),
            grass().dark().step_9(),
            indigo().dark().step_9(),
            iris().dark().step_9(),
        ]))
    }

    /// Returns the set of light accent colors.
    pub fn light() -> Self {
        Self(Arc::from(vec![
            blue().light().step_9(),
            orange().light().step_9(),
            pink().light().step_9(),
            lime().light().step_9(),
            purple().light().step_9(),
            amber().light().step_9(),
            jade().light().step_9(),
            tomato().light().step_9(),
            cyan().light().step_9(),
            gold().light().step_9(),
            grass().light().step_9(),
            indigo().light().step_9(),
            iris().light().step_9(),
        ]))
    }
}

impl AccentColors {
    /// Returns the color for the given index.
    pub fn color_for_index(&self, index: u32) -> Hsla {
        self.0[index as usize % self.0.len()]
    }

    /// Merges the given accent colors into this [`AccentColors`] instance.
    pub fn merge(&mut self, accent_colors: &[settings::AccentContent]) {
        if accent_colors.is_empty() {
            return;
        }

        let colors = accent_colors
            .iter()
            .filter_map(|accent_color| {
                accent_color
                    .0
                    .as_ref()
                    .and_then(|color| try_parse_color(color).ok())
            })
            .collect::<Vec<_>>();

        if !colors.is_empty() {
            self.0 = Arc::from(colors);
        }
    }
}
