use ratatui::Frame;
use ratatui::layout::Rect;
use ratatui::style::Style;
use ratatui::text::{Line, Span};
use ratatui::widgets::{Paragraph, Scrollbar, ScrollbarOrientation, ScrollbarState};

use crate::theme::ThemePalette;

pub struct HorizontalScrollParams {
    pub position: usize,
    pub viewport_size: usize,
    pub total_items: usize,
}

pub fn render_horizontal_scroll_indicator(
    frame: &mut Frame,
    area: Rect,
    params: HorizontalScrollParams,
    theme: &ThemePalette,
) {
    if params.total_items <= params.viewport_size {
        return;
    }

    let can_scroll_left = params.position > 0;
    let can_scroll_right = params.position + params.viewport_size < params.total_items;

    if !can_scroll_left && !can_scroll_right {
        return;
    }

    let left_margin: u16 = 1;
    let available_width = area.width.saturating_sub(left_margin) as usize;
    if available_width < 15 {
        return;
    }

    let scrollable_range = params.total_items.saturating_sub(params.viewport_size);
    let percentage = (params.position * 100)
        .checked_div(scrollable_range)
        .unwrap_or(0);
    let position_text = format!("col {:>3}%", percentage.min(100));

    // Layout: [col XXX%][space][scrollbar with < and >][1-cell gap for border]
    let fixed_parts_len = position_text.len() + 1 + 1;
    let scrollbar_width = available_width.saturating_sub(fixed_parts_len).max(5);

    let text_style = Style::default().fg(theme.component.navigation.scrollbar_active);

    let position_span = Span::styled(format!("{position_text} "), text_style);

    let text_line = Line::from(vec![position_span]);

    let text_area = Rect {
        x: area.x + left_margin,
        y: area.y + area.height.saturating_sub(1),
        width: (text_line.width() as u16).min(area.width),
        height: 1,
    };
    frame.render_widget(Paragraph::new(text_line), text_area);

    let scrollbar_area = Rect {
        x: text_area.x + text_area.width,
        y: text_area.y,
        width: scrollbar_width as u16,
        height: 1,
    };

    let arrow_active = Style::default().fg(theme.component.navigation.scrollbar_active);
    let arrow_inactive = Style::default().fg(theme.component.navigation.scrollbar_inactive);

    let scrollbar = Scrollbar::new(ScrollbarOrientation::HorizontalBottom)
        .thumb_symbol("═")
        .track_symbol(Some("─"))
        .begin_symbol(Some("◀︎"))
        .end_symbol(Some("▶︎"))
        .thumb_style(Style::default().fg(theme.component.navigation.scrollbar_active))
        .track_style(Style::default().fg(theme.component.navigation.scrollbar_inactive))
        .begin_style(if can_scroll_left {
            arrow_active
        } else {
            arrow_inactive
        })
        .end_style(if can_scroll_right {
            arrow_active
        } else {
            arrow_inactive
        });

    // Workaround for Ratatui scrollbar bug (issue #1681):
    // content_length should be the scrollable range, not total items
    let scrollable_range = params.total_items.saturating_sub(params.viewport_size);
    let mut scrollbar_state = ScrollbarState::default()
        .content_length(scrollable_range)
        .viewport_content_length(0) // Use default (track size)
        .position(params.position);

    frame.render_stateful_widget(scrollbar, scrollbar_area, &mut scrollbar_state);
}

pub struct VerticalScrollParams {
    pub position: usize,
    pub viewport_size: usize,
    pub total_items: usize,
    pub has_horizontal_scrollbar: bool,
}

pub fn render_vertical_scroll_indicator_bar(
    frame: &mut Frame,
    area: Rect,
    params: VerticalScrollParams,
    theme: &ThemePalette,
) {
    if params.total_items <= params.viewport_size {
        return;
    }

    let can_scroll_up = params.position > 0;
    let can_scroll_down = params.position + params.viewport_size < params.total_items;

    if !can_scroll_up && !can_scroll_down {
        return;
    }

    // Reserve 1 row at bottom when horizontal scrollbar is also present
    let height = if params.has_horizontal_scrollbar {
        area.height.saturating_sub(1)
    } else {
        area.height
    };

    if height < 3 {
        return;
    }

    let scrollbar_area = Rect {
        x: area.x + area.width.saturating_sub(1),
        y: area.y,
        width: 1,
        height,
    };

    let arrow_active = Style::default().fg(theme.component.navigation.scrollbar_active);
    let arrow_inactive = Style::default().fg(theme.component.navigation.scrollbar_inactive);

    let scrollbar = Scrollbar::new(ScrollbarOrientation::VerticalRight)
        .thumb_symbol("┃")
        .track_symbol(Some("│"))
        .begin_symbol(Some("▲"))
        .end_symbol(Some("▼"))
        .thumb_style(Style::default().fg(theme.component.navigation.scrollbar_active))
        .track_style(Style::default().fg(theme.component.navigation.scrollbar_inactive))
        .begin_style(if can_scroll_up {
            arrow_active
        } else {
            arrow_inactive
        })
        .end_style(if can_scroll_down {
            arrow_active
        } else {
            arrow_inactive
        });

    // Workaround for Ratatui scrollbar bug (issue #1681):
    // content_length should be the scrollable range, not total items
    let scrollable_range = params.total_items.saturating_sub(params.viewport_size);
    let mut scrollbar_state = ScrollbarState::default()
        .content_length(scrollable_range)
        .viewport_content_length(0) // Use default (track size)
        .position(params.position);

    frame.render_stateful_widget(scrollbar, scrollbar_area, &mut scrollbar_state);
}

pub fn clamp_scroll_offset(
    scroll_offset: usize,
    viewport_size: usize,
    total_items: usize,
) -> usize {
    scroll_offset.min(total_items.saturating_sub(viewport_size))
}

#[cfg(test)]
mod tests {
    use super::clamp_scroll_offset;

    #[test]
    fn clamp_returns_zero_when_content_fits() {
        assert_eq!(clamp_scroll_offset(100, 10, 5), 0);
    }

    #[test]
    fn clamp_returns_zero_when_exact_fit() {
        assert_eq!(clamp_scroll_offset(5, 10, 10), 0);
    }

    #[test]
    fn clamp_preserves_offset_within_range() {
        assert_eq!(clamp_scroll_offset(50, 10, 100), 50);
    }

    #[test]
    fn clamp_caps_offset_exceeding_max() {
        assert_eq!(clamp_scroll_offset(100, 10, 20), 10);
    }
}
