//! Application state template for tool TUI integration
//!
//! Copy and customize this template for your tool's app state.
//! Replace {{TOOL_NAME}} with your tool name (e.g., MyTool, TrackingManager, etc.)
//! Replace {{ITEM_TYPE}} with your primary data type

use serde::{Deserialize, Serialize};
use std::fmt;

/// Screen types - customize based on your tool's screens
///
/// # Example
/// ```ignore
/// pub enum ScreenType {
///     List,        // Show all items
///     Detail,      // Show item details
///     Create,      // Create new item
///     Settings,    // Tool settings
/// }
/// ```
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum ScreenType {
    /// List screen - show all items
    List,
    /// Detail screen - show item details
    Detail,
    /// Create screen - create new items
    Create,
}

impl fmt::Display for ScreenType {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            ScreenType::List => write!(f, "List"),
            ScreenType::Detail => write!(f, "Detail"),
            ScreenType::Create => write!(f, "Create"),
        }
    }
}

/// Application state - manages all mutable state
///
/// # Design Pattern: R-STATE-SEPARATION
/// All state mutations go through explicit methods. Rendering functions
/// only read state (take `&AppState`, never `&mut AppState`).
///
/// # Dirty Flag
/// The `dirty` flag tracks whether state changed since last render.
/// Only redraw when `dirty` is true, then set to false.
#[derive(Clone, Debug)]
pub struct AppState {
    /// Current screen (navigation state)
    pub current_screen: ScreenType,

    /// Primary items collection - customize type as needed
    pub items: Vec<String>,

    /// Currently selected item index
    pub selected_index: usize,

    /// Whether state changed (needs redraw)
    pub dirty: bool,

    /// Whether application should quit
    pub should_quit: bool,

    // === Form fields for create/edit ===
    /// Form input: item name
    pub form_name: String,
    /// Form input: item description
    pub form_description: String,
}

impl AppState {
    /// Create new application state
    pub fn new() -> Self {
        AppState {
            current_screen: ScreenType::List,
            items: Vec::new(),
            selected_index: 0,
            dirty: true,
            should_quit: false,
            form_name: String::new(),
            form_description: String::new(),
        }
    }

    // === Item Management ===

    /// Add a new item to the collection
    pub fn add_item(&mut self, item: String) {
        self.items.push(item);
        self.dirty = true;
    }

    /// Get currently selected item
    pub fn selected_item(&self) -> Option<&String> {
        self.items.get(self.selected_index)
    }

    // === Navigation ===

    /// Select next item in list
    pub fn select_next(&mut self) {
        if !self.items.is_empty() {
            self.selected_index = (self.selected_index + 1) % self.items.len();
            self.dirty = true;
        }
    }

    /// Select previous item in list
    pub fn select_previous(&mut self) {
        if !self.items.is_empty() {
            self.selected_index = if self.selected_index == 0 {
                self.items.len() - 1
            } else {
                self.selected_index - 1
            };
            self.dirty = true;
        }
    }

    /// Switch to a different screen
    pub fn set_screen(&mut self, screen: ScreenType) {
        if self.current_screen != screen {
            self.current_screen = screen;
            self.dirty = true;
        }
    }

    // === Form Management ===

    /// Reset form fields to empty
    pub fn reset_form(&mut self) {
        self.form_name.clear();
        self.form_description.clear();
        self.dirty = true;
    }

    // === Lifecycle ===

    /// Request application quit
    pub fn request_quit(&mut self) {
        self.should_quit = true;
    }

    /// Check if state has changed since last render
    pub fn is_dirty(&self) -> bool {
        self.dirty
    }

    /// Mark state as rendered (clear dirty flag)
    ///
    /// Call this after successfully rendering to the terminal
    pub fn reset_dirty(&mut self) {
        self.dirty = false;
    }

    /// Check if should quit
    pub fn should_quit(&self) -> bool {
        self.should_quit
    }
}

impl Default for AppState {
    fn default() -> Self {
        Self::new()
    }
}

// ============================================================================
// Tests - Minimum 15+ tests per module
// ============================================================================

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

    // === Initialization Tests ===

    #[test]
    fn test_app_state_new() {
        let state = AppState::new();
        assert_eq!(state.current_screen, ScreenType::List);
        assert!(state.items.is_empty());
        assert_eq!(state.selected_index, 0);
        assert!(state.dirty);
        assert!(!state.should_quit);
        assert!(state.form_name.is_empty());
    }

    #[test]
    fn test_app_state_default() {
        let state = AppState::default();
        assert_eq!(state.current_screen, ScreenType::List);
    }

    // === Item Management Tests ===

    #[test]
    fn test_add_item() {
        let mut state = AppState::new();
        state.add_item("Item 1".to_string());
        assert_eq!(state.items.len(), 1);
        assert!(state.dirty);
    }

    #[test]
    fn test_selected_item() {
        let mut state = AppState::new();
        state.add_item("Item 1".to_string());
        assert_eq!(state.selected_item(), Some(&"Item 1".to_string()));
    }

    #[test]
    fn test_selected_item_none() {
        let state = AppState::new();
        assert!(state.selected_item().is_none());
    }

    // === Navigation Tests ===

    #[test]
    fn test_select_next() {
        let mut state = AppState::new();
        state.add_item("Item 1".to_string());
        state.add_item("Item 2".to_string());
        state.reset_dirty();

        state.select_next();
        assert_eq!(state.selected_index, 1);
        assert!(state.dirty);
    }

    #[test]
    fn test_select_next_wraps() {
        let mut state = AppState::new();
        state.add_item("Item 1".to_string());
        state.add_item("Item 2".to_string());
        state.selected_index = 1;
        state.reset_dirty();

        state.select_next();
        assert_eq!(state.selected_index, 0);
    }

    #[test]
    fn test_select_previous() {
        let mut state = AppState::new();
        state.add_item("Item 1".to_string());
        state.add_item("Item 2".to_string());
        state.selected_index = 1;
        state.reset_dirty();

        state.select_previous();
        assert_eq!(state.selected_index, 0);
    }

    #[test]
    fn test_select_previous_wraps() {
        let mut state = AppState::new();
        state.add_item("Item 1".to_string());
        state.add_item("Item 2".to_string());
        state.reset_dirty();

        state.select_previous();
        assert_eq!(state.selected_index, 1);
    }

    // === Screen Navigation Tests ===

    #[test]
    fn test_set_screen() {
        let mut state = AppState::new();
        state.reset_dirty();

        state.set_screen(ScreenType::Detail);
        assert_eq!(state.current_screen, ScreenType::Detail);
        assert!(state.dirty);
    }

    #[test]
    fn test_set_screen_same_not_dirty() {
        let mut state = AppState::new();
        state.reset_dirty();

        state.set_screen(ScreenType::List);
        assert!(!state.dirty);
    }

    // === Form Management Tests ===

    #[test]
    fn test_reset_form() {
        let mut state = AppState::new();
        state.form_name = "Test".to_string();
        state.form_description = "Description".to_string();
        state.reset_dirty();

        state.reset_form();
        assert!(state.form_name.is_empty());
        assert!(state.form_description.is_empty());
        assert!(state.dirty);
    }

    // === Lifecycle Tests ===

    #[test]
    fn test_request_quit() {
        let mut state = AppState::new();
        assert!(!state.should_quit());

        state.request_quit();
        assert!(state.should_quit());
    }

    #[test]
    fn test_dirty_flag() {
        let mut state = AppState::new();
        assert!(state.is_dirty());

        state.reset_dirty();
        assert!(!state.is_dirty());
    }
}
