use crate::Color;
use crate::{
    hash,
    types::{Rect, Vector2},
    Id, Layout, Ui,
};

pub struct ComboBox<'a, 'b, 'c> {
    id: Id,
    label: &'a str,
    variants: &'b [&'c str],
}

impl<'a, 'b, 'c> ComboBox<'a, 'b, 'c> {
    pub fn new(id: Id, variants: &'b [&'c str]) -> ComboBox<'a, 'b, 'c> {
        ComboBox {
            id,
            label: "",
            variants,
        }
    }

    pub fn label<'x>(self, label: &'x str) -> ComboBox<'x, 'b, 'c> {
        ComboBox {
            id: self.id,
            variants: self.variants,
            label,
        }
    }

    pub fn ui(self, ui: &mut Ui, data: &mut usize) -> usize {
        let context = ui.get_active_window_context();

        let size = Vector2::new(
            context.window.cursor.area.w
                - context.global_style.margin * 2.
                - context.window.cursor.ident,
            19.,
        );
        let pos = context.window.cursor.fit(size, Layout::Vertical);

        let active_area_w = size.x / 2.;
        let triangle_area_w = 19.;

        let clickable_rect = Rect::new(pos.x, pos.y, active_area_w, size.y);
        let hovered = clickable_rect.contains(context.input.mouse_position);

        let state = context
            .storage_any
            .get_or_default::<bool>(hash!(self.id, "combobox_state"));

        if context.window.was_active == false {
            *state = false;
        }
        context.window.draw_commands.draw_rect(
            clickable_rect,
            context.global_style.editbox_background(context.focused),
            None,
        );
        context.window.draw_commands.draw_label(
            self.variants[*data],
            Vector2::new(pos.x + 5., pos.y + 2.),
            Color::from_rgba(0, 0, 0, 255),
        );

        context.window.draw_commands.draw_rect(
            Rect::new(
                pos.x + active_area_w - triangle_area_w,
                pos.y,
                triangle_area_w,
                size.y,
            ),
            context.global_style.editbox_background(context.focused),
            None,
        );
        context.window.draw_commands.draw_triangle(
            Vector2::new(pos.x + active_area_w - triangle_area_w + 4.0, pos.y + 4.0),
            Vector2::new(pos.x + active_area_w - 4.0, pos.y + 4.0),
            Vector2::new(pos.x + active_area_w - triangle_area_w / 2.0, pos.y + 15.0),
            Color::new(0.7, 0.7, 0.7, 1.0),
        );

        context.window.draw_commands.draw_label(
            self.label,
            Vector2::new(pos.x + size.x / 2. + 5., pos.y + 2.),
            Color::from_rgba(0, 0, 0, 255),
        );

        if context.focused && hovered && context.input.click_up {
            *state ^= true;
        }

        let modal_size = Vector2::new(200.0, self.variants.len() as f32 * 20.0 + 20.0);
        let modal_rect = Rect::new(pos.x, pos.y, modal_size.x, modal_size.y);
        if *state
            && (context.input.escape
                || context.input.enter
                || (modal_rect.contains(context.input.mouse_position) == false
                    && context.input.click_down))
        {
            *state = false;
        }

        if *state {
            let context = ui.begin_modal(hash!("combobox", self.id), pos, modal_size);

            let state = context
                .storage_any
                .get_or_default::<bool>(hash!(self.id, "combobox_state"));

            for (i, variant) in self.variants.iter().enumerate() {
                let rect = Rect::new(
                    pos.x + 5.0,
                    pos.y + i as f32 * 20.0 + 20.0,
                    active_area_w - 5.0,
                    20.0,
                );
                let hovered = rect.contains(context.input.mouse_position);

                context.window.draw_commands.draw_rect(
                    rect,
                    context
                        .global_style
                        .combobox_variant_border(hovered, *data == i),
                    context
                        .global_style
                        .combobox_variant_background(hovered, *data == i),
                );

                context.window.draw_commands.draw_label(
                    variant,
                    Vector2::new(pos.x + 7., pos.y + i as f32 * 20.0 + 20.0 + 2.0),
                    Color::from_rgba(0, 0, 0, 255),
                );

                if hovered && context.input.click_up {
                    *data = i;
                    *state = false;
                }
            }
            ui.end_modal();
        }

        *data
    }
}

impl Ui {
    pub fn combo_box<'a>(
        &mut self,
        id: Id,
        label: &str,
        variants: &[&str],
        data: impl Into<Option<&'a mut usize>>,
    ) -> usize {
        if let Some(r) = data.into() {
            ComboBox::new(id, variants).label(label).ui(self, r)
        } else {
            let data_id = hash!(id, "selected_variant");
            let mut selected_variant = { *self.get_any(data_id) };

            ComboBox::new(id, variants)
                .label(label)
                .ui(self, &mut selected_variant);

            *self.get_any(data_id) = selected_variant;

            selected_variant
        }
    }
}
