use crate::component_prelude::*;
use crate::prelude::*;
use gpui::{AnyElement, StyleRefinement};
use smallvec::SmallVec;

use super::Avatar;

/// An element that displays a collection of (usually) faces stacked
/// horizontally, with the left-most face on top, visually descending
/// from left to right.
///
/// Facepiles are used to display a group of people or things,
/// such as a list of participants in a collaboration session.
///
/// # Examples
///
/// ## Default
///
/// A default, horizontal facepile.
///
/// ```
/// use gpui::IntoElement;
/// use ui::{Avatar, Facepile, EXAMPLE_FACES};
///
/// let facepile = Facepile::new(
///     EXAMPLE_FACES.iter().take(3).map(|&url|
///         Avatar::new(url).into_any_element()).collect()
/// );
/// ```
#[derive(IntoElement, Documented, RegisterComponent)]
pub struct Facepile {
    base: Div,
    faces: SmallVec<[AnyElement; 2]>,
}

impl Facepile {
    /// Creates a new empty facepile.
    pub fn empty() -> Self {
        Self::new(SmallVec::new())
    }

    /// Creates a new facepile with the given faces.
    pub fn new(faces: SmallVec<[AnyElement; 2]>) -> Self {
        Self { base: div(), faces }
    }
}

impl ParentElement for Facepile {
    fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
        self.faces.extend(elements);
    }
}

// Style methods.
impl Facepile {
    fn style(&mut self) -> &mut StyleRefinement {
        self.base.style()
    }

    gpui::padding_style_methods!({
        visibility: pub
    });
}

impl RenderOnce for Facepile {
    fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
        // Lay the faces out in reverse so they overlap in the desired order (left to right, front to back)
        self.base
            .flex()
            .flex_row_reverse()
            .items_center()
            .justify_start()
            .children(
                self.faces
                    .into_iter()
                    .enumerate()
                    .rev()
                    .map(|(ix, player)| div().when(ix > 0, |div| div.ml_neg_1()).child(player)),
            )
    }
}

pub const EXAMPLE_FACES: [&str; 6] = [
    "https://avatars.githubusercontent.com/u/326587?s=60&v=4",
    "https://avatars.githubusercontent.com/u/2280405?s=60&v=4",
    "https://avatars.githubusercontent.com/u/1789?s=60&v=4",
    "https://avatars.githubusercontent.com/u/67129314?s=60&v=4",
    "https://avatars.githubusercontent.com/u/482957?s=60&v=4",
    "https://avatars.githubusercontent.com/u/1714999?s=60&v=4",
];

impl Component for Facepile {
    fn scope() -> ComponentScope {
        ComponentScope::Collaboration
    }

    fn description() -> Option<&'static str> {
        Some(
            "Displays a collection of avatars or initials in a compact format. Often used to represent active collaborators or a subset of contributors.",
        )
    }

    fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
        Some(
            v_flex()
                .gap_6()
                .children(vec![example_group_with_title(
                    "Facepile Examples",
                    vec![
                        single_example(
                            "Default",
                            Facepile::new(
                                EXAMPLE_FACES
                                    .iter()
                                    .map(|&url| Avatar::new(url).into_any_element())
                                    .collect(),
                            )
                            .into_any_element(),
                        ),
                        single_example(
                            "Custom Size",
                            Facepile::new(
                                EXAMPLE_FACES
                                    .iter()
                                    .map(|&url| Avatar::new(url).size(px(24.)).into_any_element())
                                    .collect(),
                            )
                            .into_any_element(),
                        ),
                    ],
                )])
                .into_any_element(),
        )
    }
}
