//! TUI configuration for the unified config.toml file.
//!
//! This module defines the `[tui]` section of the unified config file.
//! TUI-specific types (SessionField, SortColumn, etc.) remain in mi6-tui,
//! but this module uses string-based representations for portability.

use std::collections::HashMap;

use serde::{Deserialize, Serialize};

/// Current TUI config version.
///
/// ## Versioning Strategy
/// - Bump when making **breaking changes**: removing/renaming fields, changing semantics
/// - Do NOT bump for **additive changes**: new optional fields with defaults
///
/// ## Version History
/// - Version 1: Original JSON format with numeric column indices
/// - Version 2: JSON format with SessionField enum values
/// - Version 3: Unified TOML format (current)
pub const CURRENT_TUI_CONFIG_VERSION: u32 = 3;

/// TUI configuration section for the unified config.
///
/// This struct is designed to be serialized as the `[tui]` section in config.toml.
/// It stores values in a format that can be serialized/deserialized without
/// depending on TUI-specific types like SessionField.
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct TuiConfig {
    /// Config version for migrations.
    #[serde(default)]
    pub version: Option<u32>,

    /// Column visibility settings (one bool per column).
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub column_visibility: Vec<bool>,

    /// Column display order (field names as strings).
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub column_order: Vec<String>,

    /// Refresh interval in milliseconds.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub refresh_interval_ms: Option<u64>,

    /// Transcript poll interval in milliseconds.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub transcript_poll_interval_ms: Option<u64>,

    /// Theme name (e.g., "default", "minimal", "dracula").
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub theme: Option<String>,

    /// Override for border visibility.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub show_borders: Option<bool>,

    /// Named column profiles.
    /// Each profile contains visibility and order settings.
    #[serde(default, skip_serializing_if = "HashMap::is_empty")]
    pub profiles: HashMap<String, TuiColumnProfile>,

    /// Whether the group panel is enabled/visible.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub group_panel_enabled: Option<bool>,

    /// Whether animations are enabled (e.g., panel slide transitions).
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub animation_enabled: Option<bool>,

    /// Animation duration in milliseconds.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub animation_duration_ms: Option<u64>,

    /// Sort specification - list of sort columns with direction.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub sort_spec: Option<Vec<TuiSortSpec>>,

    /// Whether to auto-enable newly detected frameworks.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub auto_enable_frameworks: Option<bool>,

    /// Method for spawning new terminals.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub terminal_spawn_method: Option<String>,

    /// Whether to shorten model names (e.g., "gpt-5.2-codex" → "gpt-5.2").
    /// Defaults to true.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub shorten_model_names: Option<bool>,

    /// Whether to check for updates on startup.
    /// Defaults to true. When enabled, mi6 will check for new versions in the background
    /// on startup and notify if an update is available.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub check_for_updates: Option<bool>,

    /// Whether to use theme-defined pane background colors.
    /// Defaults to false for backward compatibility (uses terminal default).
    /// When enabled, uses the theme's `[panes]` and `[core]` background colors.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub pane_backgrounds: Option<bool>,
}

/// Column profile stored in TOML format.
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct TuiColumnProfile {
    /// Column visibility for this profile.
    #[serde(default)]
    pub visibility: Vec<bool>,

    /// Column order for this profile (field names as strings).
    #[serde(default)]
    pub order: Vec<String>,
}

/// Sort specification for a single column.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct TuiSortSpec {
    /// Field name to sort by (e.g., "cpu", "memory", "age").
    pub field: String,

    /// Sort order: "ascending" or "descending".
    pub order: String,
}

impl TuiConfig {
    /// Check if the config is empty (all fields are default/None).
    pub fn is_empty(&self) -> bool {
        self.version.is_none()
            && self.column_visibility.is_empty()
            && self.column_order.is_empty()
            && self.refresh_interval_ms.is_none()
            && self.transcript_poll_interval_ms.is_none()
            && self.theme.is_none()
            && self.show_borders.is_none()
            && self.profiles.is_empty()
            && self.group_panel_enabled.is_none()
            && self.animation_enabled.is_none()
            && self.animation_duration_ms.is_none()
            && self.sort_spec.is_none()
            && self.auto_enable_frameworks.is_none()
            && self.terminal_spawn_method.is_none()
            && self.shorten_model_names.is_none()
            && self.check_for_updates.is_none()
            && self.pane_backgrounds.is_none()
    }
}

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

    #[test]
    fn test_tui_config_default_is_empty() {
        let config = TuiConfig::default();
        assert!(config.is_empty());
    }

    #[test]
    fn test_tui_config_serde_roundtrip() {
        let config = TuiConfig {
            version: Some(CURRENT_TUI_CONFIG_VERSION),
            column_visibility: vec![true, false, true],
            column_order: vec!["pid".to_string(), "status".to_string(), "age".to_string()],
            refresh_interval_ms: Some(1000),
            transcript_poll_interval_ms: Some(5000),
            theme: Some("dracula".to_string()),
            show_borders: Some(true),
            profiles: HashMap::new(),
            group_panel_enabled: Some(true),
            animation_enabled: Some(true),
            animation_duration_ms: Some(220),
            sort_spec: Some(vec![TuiSortSpec {
                field: "cpu".to_string(),
                order: "descending".to_string(),
            }]),
            auto_enable_frameworks: Some(false),
            terminal_spawn_method: Some("new_mux_pane".to_string()),
            shorten_model_names: Some(true),
            check_for_updates: Some(true),
            pane_backgrounds: Some(false),
        };

        let toml_str = toml::to_string_pretty(&config).unwrap();
        let parsed: TuiConfig = toml::from_str(&toml_str).unwrap();

        assert_eq!(parsed.version, config.version);
        assert_eq!(parsed.column_visibility, config.column_visibility);
        assert_eq!(parsed.column_order, config.column_order);
        assert_eq!(parsed.theme, config.theme);
        assert_eq!(parsed.refresh_interval_ms, config.refresh_interval_ms);
    }

    #[test]
    fn test_tui_config_empty_fields_not_serialized() {
        let config = TuiConfig {
            theme: Some("default".to_string()),
            ..Default::default()
        };

        let toml_str = toml::to_string_pretty(&config).unwrap();
        // Empty fields should not appear in output
        assert!(!toml_str.contains("column_visibility"));
        assert!(!toml_str.contains("profiles"));
        // But theme should appear
        assert!(toml_str.contains("theme"));
    }
}
