use ratatui::{
    buffer::Buffer,
    layout::Rect,
    style::{Color, Style},
    widgets::{Block, Borders, Widget},
};

use crate::ui::app::AppMode;

/// Trait for panel-specific content. Implement this to create a new side panel.
pub trait PanelContent {
    /// Whether the panel should appear active given the current mode.
    fn is_active(&self, mode: &AppMode) -> bool;
    /// Color used for the active border AND the selection highlight background.
    fn active_color(&self) -> Color;
    /// Block title string (include surrounding spaces for padding).
    fn title(&self) -> &str;
    /// Number of renderable rows.
    fn item_count(&self) -> usize;
    /// Message shown when `item_count()` returns 0.
    fn empty_message(&self) -> &str;
    /// Render a single item at the given row index.
    /// `inner` is the full inner area of the panel; the item occupies row `index`.
    fn render_item(&self, index: usize, is_selected: bool, inner: Rect, buf: &mut Buffer);
    /// Number of lines the footer occupies (used to reserve space).
    fn footer_height(&self) -> u16 {
        0
    }
    /// Optional footer rendered in the reserved space at the bottom.
    fn render_footer(&self, _inner: Rect, _buf: &mut Buffer) {}
}

/// Generic side-panel widget that delegates content rendering to a `PanelContent` impl.
pub struct Panel<'a, C: PanelContent> {
    content: C,
    mode: &'a AppMode,
    cursor: usize,
}

impl<'a, C: PanelContent> Panel<'a, C> {
    pub fn new(content: C, mode: &'a AppMode, cursor: usize) -> Self {
        Self {
            content,
            mode,
            cursor,
        }
    }
}

impl<C: PanelContent> Widget for Panel<'_, C> {
    fn render(self, area: Rect, buf: &mut Buffer) {
        let is_active = self.content.is_active(self.mode);
        let border_style = if is_active {
            Style::default().fg(self.content.active_color())
        } else {
            Style::default().fg(Color::DarkGray)
        };

        let block = Block::default()
            .borders(Borders::ALL)
            .border_style(border_style)
            .title(self.content.title());
        let inner = block.inner(area);
        block.render(area, buf);

        if self.content.item_count() == 0 {
            buf.set_string(
                inner.x,
                inner.y,
                self.content.empty_message(),
                Style::default().fg(Color::DarkGray),
            );
            return;
        }

        let item_height = inner.height.saturating_sub(self.content.footer_height());
        for i in 0..self.content.item_count() {
            if i as u16 >= item_height {
                break;
            }
            let is_selected = i == self.cursor && is_active;
            self.content.render_item(i, is_selected, inner, buf);
        }

        self.content.render_footer(inner, buf);
    }
}
