use crossterm::event::{KeyCode, KeyEvent};
use ratatui::{
    layout::Rect,
    style::{Color, Style},
    widgets::{Block, Borders, Clear, List, ListItem, Paragraph},
    Frame,
};

/// Event returned from selector key handling.
#[derive(Debug)]
pub enum SelectorEvent {
    /// Key was not consumed (not focused or irrelevant).
    None,
    /// Key was consumed but no selection change.
    Consumed,
    /// An item was selected — contains the index.
    Selected(usize),
}

/// A focusable popup-list selector widget.
///
/// Closed: renders as a single-line display showing the selected item label.
/// Open: renders as a bordered List overlay showing all items.
pub struct SelectorWidget<T: Clone> {
    pub title: String,
    pub items: Vec<(String, T)>,
    pub selected_idx: Option<usize>,
    pub highlighted_idx: usize,
    pub is_open: bool,
    pub is_focused: bool,
}

impl<T: Clone> SelectorWidget<T> {
    pub fn new(title: impl Into<String>) -> Self {
        Self {
            title: title.into(),
            items: Vec::new(),
            selected_idx: None,
            highlighted_idx: 0,
            is_open: false,
            is_focused: false,
        }
    }

    pub fn set_items(&mut self, items: Vec<(String, T)>) {
        self.items = items;
        self.selected_idx = None;
        self.highlighted_idx = 0;
    }

    pub fn selected_value(&self) -> Option<&T> {
        self.selected_idx
            .and_then(|i| self.items.get(i).map(|(_, v)| v))
    }

    pub fn selected_label(&self) -> &str {
        self.selected_idx
            .and_then(|i| self.items.get(i))
            .map(|(label, _)| label.as_str())
            .unwrap_or("-- None --")
    }

    /// Handle a key event. Returns a SelectorEvent indicating what happened.
    pub fn handle_key(&mut self, key: KeyEvent) -> SelectorEvent {
        if !self.is_focused {
            return SelectorEvent::None;
        }

        if !self.is_open {
            match key.code {
                KeyCode::Enter | KeyCode::Char(' ') => {
                    self.is_open = true;
                    self.highlighted_idx = self.selected_idx.unwrap_or(0);
                    return SelectorEvent::Consumed;
                }
                _ => return SelectorEvent::None,
            }
        }

        // Popup is open
        match key.code {
            KeyCode::Char('j') | KeyCode::Down => {
                if !self.items.is_empty() {
                    self.highlighted_idx = (self.highlighted_idx + 1) % self.items.len();
                }
                SelectorEvent::Consumed
            }
            KeyCode::Char('k') | KeyCode::Up => {
                if !self.items.is_empty() {
                    self.highlighted_idx = self
                        .highlighted_idx
                        .checked_sub(1)
                        .unwrap_or(self.items.len().saturating_sub(1));
                }
                SelectorEvent::Consumed
            }
            KeyCode::Enter => {
                if !self.items.is_empty() {
                    self.selected_idx = Some(self.highlighted_idx);
                    self.is_open = false;
                    return SelectorEvent::Selected(self.highlighted_idx);
                }
                SelectorEvent::Consumed
            }
            KeyCode::Esc => {
                self.is_open = false;
                SelectorEvent::Consumed
            }
            _ => SelectorEvent::Consumed, // consume all keys when open
        }
    }

    /// Render the closed (single-line) view into `area`.
    pub fn render_closed(&self, frame: &mut Frame, area: Rect) {
        let style = if self.is_focused {
            Style::default().fg(Color::Yellow)
        } else {
            Style::default()
        };
        let label = format!("{}: {}", self.title, self.selected_label());
        let widget = Paragraph::new(label)
            .style(style)
            .block(Block::default().borders(Borders::ALL));
        frame.render_widget(widget, area);
    }

    /// Render the popup overlay. Call AFTER rendering main content.
    /// `anchor` is the area the popup appears below.
    pub fn render_popup(&self, frame: &mut Frame, anchor: Rect) {
        if !self.is_open {
            return;
        }

        let popup_height = (self.items.len() as u16 + 2).min(20);
        let popup_area = Rect {
            x: anchor.x,
            y: anchor.y + anchor.height,
            width: anchor.width,
            height: popup_height.min(frame.area().height.saturating_sub(anchor.y + anchor.height)),
        };

        if popup_area.height < 3 {
            return;
        }

        frame.render_widget(Clear, popup_area);

        let items: Vec<ListItem> = self
            .items
            .iter()
            .enumerate()
            .map(|(i, (label, _))| {
                let style = if i == self.highlighted_idx {
                    Style::default().bg(Color::Blue).fg(Color::White)
                } else {
                    Style::default()
                };
                ListItem::new(label.as_str()).style(style)
            })
            .collect();

        let list = List::new(items)
            .block(Block::default().borders(Borders::ALL).title(self.title.as_str()));
        frame.render_widget(list, popup_area);
    }
}
