/// Application state machine for the TUI.
use ph_cli_core::models::{Post, PostDetail, SearchResult};

/// The current page/mode of the application.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AppMode {
    /// Three-panel home view (list + content + comments).
    Home,
    /// Search overlay.
    Search,
    /// OAuth login flow display.
    Login,
    /// Help / keybindings overlay.
    Help,
    /// Loading indicator.
    #[allow(dead_code)]
    Loading,
    /// Error display.
    Error,
}

/// The application state.
pub struct App {
    pub mode: AppMode,
    pub should_quit: bool,
    pub posts: Vec<Post>,
    pub selected_index: usize,
    pub search_input: String,
    pub search_results: Vec<SearchResult>,
    /// Loaded post detail (comments shown in right panel).
    pub current_post: Option<PostDetail>,
    pub comment_scroll: u16,
    pub loading: bool,
    pub error_message: Option<String>,
    pub status_message: Option<String>,
    pub viewport_height: u16,
    pub viewport_width: u16,
    pub spinner_tick: usize,
}

impl App {
    pub fn new() -> Self {
        Self {
            mode: AppMode::Home,
            should_quit: false,
            posts: Vec::new(),
            selected_index: 0,
            search_input: String::new(),
            search_results: Vec::new(),
            current_post: None,
            comment_scroll: 0,
            loading: false,
            error_message: None,
            status_message: None,
            viewport_height: 0,
            viewport_width: 0,
            spinner_tick: 0,
        }
    }

    pub fn set_size(&mut self, width: u16, height: u16) {
        self.viewport_width = width;
        self.viewport_height = height;
    }

    pub fn set_status(&mut self, msg: impl Into<String>) {
        self.status_message = Some(msg.into());
    }

    pub fn clear_status(&mut self) {
        self.status_message = None;
    }

    pub fn set_error(&mut self, msg: impl Into<String>) {
        self.error_message = Some(msg.into());
        self.mode = AppMode::Error;
    }

    pub fn set_loading(&mut self, loading: bool) {
        self.loading = loading;
        if loading {
            self.error_message = None;
        }
    }

    pub fn select_previous(&mut self) {
        if self.selected_index > 0 {
            self.selected_index -= 1;
        }
    }

    pub fn select_next(&mut self, max: usize) {
        if self.selected_index < max.saturating_sub(1) {
            self.selected_index += 1;
        }
    }

    pub fn selected_post(&self) -> Option<&Post> {
        self.posts.get(self.selected_index)
    }

    pub fn go_back(&mut self) {
        match self.mode {
            AppMode::Home => {
                self.current_post = None;
                self.comment_scroll = 0;
            }
            AppMode::Help | AppMode::Error => {
                self.mode = AppMode::Home;
            }
            AppMode::Search => {
                self.mode = AppMode::Home;
                self.search_input.clear();
                self.search_results.clear();
            }
            AppMode::Login => {
                self.mode = AppMode::Home;
            }
            _ => {}
        }
    }

    pub fn open_search(&mut self) {
        self.mode = AppMode::Search;
        self.search_input.clear();
        self.search_results.clear();
    }

    pub fn open_help(&mut self) {
        self.mode = AppMode::Help;
    }

    pub fn scroll_comments(&mut self, dir: i16) {
        if let Some(ref detail) = self.current_post {
            let total = count_all_comments(&detail.comments);
            let max = total.saturating_sub(1) as i16;
            self.comment_scroll = (self.comment_scroll as i16 + dir).clamp(0, max) as u16;
        }
    }
}

fn count_all_comments(comments: &[ph_cli_core::Comment]) -> usize {
    comments
        .iter()
        .map(|c| 1 + count_all_comments(&c.child_comments))
        .sum()
}
