#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub enum Page {
    #[default]
    Main,
    Patterns,
    Engine,
    Help,
    Dict,
    Options,
    Script,
}

impl Page {
    /// All pages for iteration (grid pages only — Script excluded)
    pub const ALL: &'static [Page] = &[
        Page::Main,
        Page::Patterns,
        Page::Engine,
        Page::Help,
        Page::Dict,
        Page::Options,
    ];

    /// Grid dimensions (cols, rows)
    pub const GRID_SIZE: (i8, i8) = (3, 2);

    /// Grid position (col, row) for each page
    /// Layout:
    ///         col 0      col 1       col 2
    /// row 0   Dict       Patterns    Options
    /// row 1   Help       Sequencer   Engine
    /// Script lives outside the grid at (1, 2)
    pub const fn grid_pos(self) -> (i8, i8) {
        match self {
            Page::Dict => (0, 0),
            Page::Help => (0, 1),
            Page::Patterns => (1, 0),
            Page::Main => (1, 1),
            Page::Options => (2, 0),
            Page::Engine => (2, 1),
            Page::Script => (1, 2),
        }
    }

    /// Find page at grid position, if any (grid pages only)
    pub fn at_pos(col: i8, row: i8) -> Option<Page> {
        Self::ALL.iter().copied().find(|p| p.grid_pos() == (col, row))
    }

    /// Display name for the page
    pub const fn name(self) -> &'static str {
        match self {
            Page::Main => "Sequencer",
            Page::Patterns => "Patterns",
            Page::Engine => "Engine",
            Page::Help => "Help",
            Page::Dict => "Dict",
            Page::Options => "Options",
            Page::Script => "Script",
        }
    }

    pub fn left(&mut self) {
        if *self == Page::Script {
            *self = Page::Help;
            return;
        }
        let (col, row) = self.grid_pos();
        for offset in 1..=Self::GRID_SIZE.0 {
            let new_col = (col - offset).rem_euclid(Self::GRID_SIZE.0);
            if let Some(page) = Self::at_pos(new_col, row) {
                *self = page;
                return;
            }
        }
    }

    pub fn right(&mut self) {
        if *self == Page::Script {
            *self = Page::Engine;
            return;
        }
        let (col, row) = self.grid_pos();
        for offset in 1..=Self::GRID_SIZE.0 {
            let new_col = (col + offset).rem_euclid(Self::GRID_SIZE.0);
            if let Some(page) = Self::at_pos(new_col, row) {
                *self = page;
                return;
            }
        }
    }

    pub fn up(&mut self) {
        if *self == Page::Script {
            *self = Page::Main;
            return;
        }
        let (col, row) = self.grid_pos();
        if let Some(page) = Self::at_pos(col, row - 1) {
            *self = page;
        }
    }

    pub fn down(&mut self) {
        let (col, row) = self.grid_pos();
        // From Main (1,1), going down reaches Script
        if *self == Page::Main {
            *self = Page::Script;
            return;
        }
        if let Some(page) = Self::at_pos(col, row + 1) {
            *self = page;
        }
    }

    pub const fn help_topic_index(self) -> Option<usize> {
        match self {
            Page::Main => Some(5),     // "Using the Sequencer"
            Page::Patterns => Some(3), // "Banks & Patterns"
            Page::Engine => Some(14),  // "Introduction" (Audio Engine)
            Page::Help => Some(0),     // "Welcome"
            Page::Dict => Some(7),     // "About Forth"
            Page::Options => None,
            Page::Script => None,
        }
    }

    /// Whether this page appears in the navigation minimap grid.
    pub const fn visible_in_minimap(self) -> bool {
        !matches!(self, Page::Script)
    }
}
