use nalgebra_glm::Vec2;

use super::super::layout::{Layout, LayoutAlignment};
use super::super::types::Rect;
use super::types::ImmediateUi;

impl ImmediateUi {
    pub fn separator(&mut self) {
        let width = self.layout_stack.available_width();
        let height = 1.0;

        let rect = self
            .layout_stack
            .allocate(Vec2::new(width, height + self.style.spacing * 2.0));

        self.add_rect(crate::render::wgpu::passes::geometry::UiRect {
            position: Vec2::new(rect.x(), rect.y() + self.style.spacing),
            size: Vec2::new(width, height),
            color: self.style.border_color,
            corner_radius: 0.0,
            border_width: 0.0,
            border_color: nalgebra_glm::Vec4::new(0.0, 0.0, 0.0, 0.0),
            clip_rect: None,
            ..Default::default()
        });
    }

    pub fn spacing(&mut self, amount: f32) {
        if let Some(layout) = self.layout_stack.current_mut() {
            layout.add_spacing(amount);
        }
    }

    pub fn available_width(&self) -> f32 {
        self.layout_stack.available_width()
    }

    pub fn cursor(&self) -> Vec2 {
        self.layout_stack.cursor()
    }

    pub fn spring(&mut self, following_width: f32) {
        let parent_right = {
            let stack_len = self.layout_stack.len();
            if stack_len >= 2 {
                if let Some(Layout::Panel { rect, padding, .. }) =
                    self.layout_stack.get(stack_len - 2)
                {
                    Some(rect.max.x - padding)
                } else {
                    None
                }
            } else {
                None
            }
        };
        if let Some(right) = parent_right
            && let Some(Layout::Horizontal { cursor, .. }) = self.layout_stack.current_mut()
        {
            cursor.x = right - following_width;
        }
    }

    pub fn indent(&mut self, amount: f32) {
        if let Some(layout) = self.layout_stack.current_mut() {
            let cursor = layout.cursor();
            layout.set_cursor(Vec2::new(cursor.x + amount, cursor.y));
        }
    }

    pub fn begin_vertical(&mut self, start: Vec2, width: f32) {
        self.layout_stack
            .push(Layout::vertical(start, self.style.spacing, width));
    }

    pub fn end_vertical(&mut self) {
        self.layout_stack.pop();
    }

    pub fn set_alignment(&mut self, alignment: LayoutAlignment) {
        if let Some(layout) = self.layout_stack.current_mut() {
            match layout {
                Layout::Vertical { alignment: a, .. } => *a = alignment,
                Layout::Horizontal { alignment: a, .. } => *a = alignment,
                _ => {}
            }
        }
    }

    pub fn begin_horizontal(&mut self, start: Vec2) {
        self.layout_stack
            .push(Layout::horizontal(start, self.style.spacing));
    }

    pub fn begin_horizontal_at_cursor(&mut self) {
        let cursor = self.layout_stack.cursor();
        self.layout_stack
            .push(Layout::horizontal(cursor, self.style.spacing));
    }

    pub fn end_horizontal(&mut self) {
        if let Some(Layout::Horizontal {
            max_height,
            spacing,
            ..
        }) = self.layout_stack.pop()
            && let Some(parent) = self.layout_stack.current_mut()
        {
            let advance = max_height + spacing;
            match parent {
                Layout::Vertical { cursor, .. } => cursor.y += advance,
                Layout::Panel { cursor, .. } => cursor.y += advance,
                _ => {}
            }
        }
    }

    pub fn begin_scroll_area(&mut self, id: &str, size: Vec2) {
        let scroll_id = self.make_id(id);
        let state = self.get_state(scroll_id);

        let rect = self.layout_stack.allocate(size);
        self.scroll_area_stack.push((scroll_id, rect));

        self.add_rect(crate::render::wgpu::passes::geometry::UiRect {
            position: rect.min,
            size: rect.size(),
            color: nalgebra_glm::Vec4::new(0.1, 0.1, 0.12, 1.0),
            corner_radius: self.style.corner_radius,
            border_width: self.style.border_width,
            border_color: self.style.border_color,
            clip_rect: None,
            ..Default::default()
        });

        if rect.contains(self.mouse_pos) && self.scroll_delta.y != 0.0 {
            let mut new_state = state;
            new_state.scroll_offset.y -= self.scroll_delta.y * 30.0;
            new_state.scroll_offset.y = new_state.scroll_offset.y.max(0.0);
            self.set_state(scroll_id, new_state);
        }

        let content_rect = rect.shrink(self.style.padding);
        let scrolled_rect = Rect::new(
            content_rect.x(),
            content_rect.y() - state.scroll_offset.y,
            content_rect.width(),
            10000.0,
        );

        self.push_clip(content_rect);
        self.layout_stack
            .push(Layout::panel(scrolled_rect, 0.0, self.style.spacing));
    }

    pub fn end_scroll_area(&mut self) {
        self.layout_stack.pop();
        self.pop_clip();

        if let Some((scroll_id, rect)) = self.scroll_area_stack.pop() {
            let state = self.get_state(scroll_id);
            let scrollbar_width = 8.0;
            let scrollbar_margin = 2.0;

            let content_height = state.scroll_offset.y + rect.height();
            let visible_ratio = (rect.height() / content_height).min(1.0);

            if visible_ratio < 1.0 {
                let scrollbar_height = rect.height() * visible_ratio;
                let scrollbar_max_offset = rect.height() - scrollbar_height;
                let scroll_ratio = state.scroll_offset.y / (content_height - rect.height());
                let scrollbar_y = rect.y() + scroll_ratio * scrollbar_max_offset;

                self.add_rect(crate::render::wgpu::passes::geometry::UiRect {
                    position: Vec2::new(
                        rect.max.x - scrollbar_width - scrollbar_margin,
                        scrollbar_y,
                    ),
                    size: Vec2::new(scrollbar_width, scrollbar_height),
                    color: nalgebra_glm::Vec4::new(0.4, 0.4, 0.45, 0.8),
                    corner_radius: scrollbar_width * 0.5,
                    border_width: 0.0,
                    border_color: nalgebra_glm::Vec4::new(0.0, 0.0, 0.0, 0.0),
                    clip_rect: None,
                    ..Default::default()
                });
            }
        }
    }
}
