//! Main-menu state and rendering.

use ratatui::Frame;
use ratatui::style::{Modifier, Style};
use ratatui::text::{Line, Span, Text};
use ratatui::widgets::{Block, Borders, Paragraph};

use crate::config::Palette;

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum MenuItem {
    Play,
    Replay,
    Config,
    Quit,
}

impl MenuItem {
    pub fn label(&self) -> &'static str {
        match self {
            MenuItem::Play => "Play",
            MenuItem::Replay => "Replay",
            MenuItem::Config => "Config",
            MenuItem::Quit => "Quit",
        }
    }

    pub fn enabled(&self) -> bool {
        matches!(
            self,
            MenuItem::Play | MenuItem::Replay | MenuItem::Config | MenuItem::Quit
        )
    }
}

const ITEMS: [MenuItem; 4] = [
    MenuItem::Play,
    MenuItem::Replay,
    MenuItem::Config,
    MenuItem::Quit,
];

pub struct MenuState {
    pub selected: usize,
}

impl MenuState {
    pub fn items() -> &'static [MenuItem] {
        &ITEMS
    }

    pub fn new() -> Self {
        let selected = ITEMS.iter().position(|i| i.enabled()).unwrap_or(0);
        MenuState { selected }
    }

    pub fn current(&self) -> MenuItem {
        ITEMS[self.selected]
    }

    pub fn next(&mut self) {
        let n = ITEMS.len();
        for step in 1..=n {
            let candidate = (self.selected + step) % n;
            if ITEMS[candidate].enabled() {
                self.selected = candidate;
                return;
            }
        }
    }

    pub fn previous(&mut self) {
        let n = ITEMS.len();
        for step in 1..=n {
            let candidate = (self.selected + n - step) % n;
            if ITEMS[candidate].enabled() {
                self.selected = candidate;
                return;
            }
        }
    }
}

pub fn render_menu(frame: &mut Frame, state: &MenuState, palette: &Palette) {
    let mut lines: Vec<Line> = vec![
        Line::from(Span::styled(
            "rsstacker",
            Style::default()
                .fg(palette.title)
                .add_modifier(Modifier::BOLD),
        )),
        Line::from(Span::styled(
            "terminal block-stacking practice and replay",
            Style::default().fg(palette.label),
        )),
        Line::from(""),
    ];
    for (i, item) in MenuState::items().iter().enumerate() {
        let selected = i == state.selected;
        let marker = if selected { "> " } else { "  " };
        let mut style = if item.enabled() {
            Style::default().fg(palette.text)
        } else {
            Style::default().fg(palette.muted)
        };
        if selected {
            style = style.add_modifier(Modifier::BOLD).fg(palette.highlight);
        }
        let suffix = if item.enabled() {
            ""
        } else {
            "  (coming soon)"
        };
        lines.push(Line::from(Span::styled(
            format!("{marker}{}{suffix}", item.label()),
            style,
        )));
    }
    lines.push(Line::from(""));
    lines.push(Line::from(Span::styled(
        "Up/Down move · Enter select · q quit",
        Style::default().fg(palette.muted),
    )));

    let block = Block::default().borders(Borders::ALL).title(" rsstacker ");
    let paragraph = Paragraph::new(Text::from(lines)).block(block);
    frame.render_widget(paragraph, frame.area());
}

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

    #[test]
    fn navigation_cycles_all_four_enabled_items() {
        let mut state = MenuState::new();
        assert_eq!(state.current(), MenuItem::Play);
        state.next();
        assert_eq!(state.current(), MenuItem::Replay);
        state.next();
        assert_eq!(state.current(), MenuItem::Config);
        state.next();
        assert_eq!(state.current(), MenuItem::Quit);
        state.next();
        assert_eq!(state.current(), MenuItem::Play);
        state.previous();
        assert_eq!(state.current(), MenuItem::Quit);
    }

    #[test]
    fn all_menu_items_are_enabled() {
        assert!(MenuItem::Play.enabled());
        assert!(MenuItem::Replay.enabled());
        assert!(MenuItem::Config.enabled());
        assert!(MenuItem::Quit.enabled());
    }
}
