trx-cli 0.1.10

A Modern Cross-Platform Package Manager TUI
use serde::{Deserialize, Serialize};
use std::fs;
use directories::ProjectDirs;
use ratatui::style::Color;

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Settings {
    pub search_debounce_ms: u64,
    pub auto_update_check: bool,
    pub auto_cleanup: bool,
    pub default_tab: String,
    pub max_search_results: usize,
    pub enabled_managers: Vec<String>,
    pub border_style: String, // "Plain", "Rounded", "Double", "Thick"
    pub spinner_type: String, // "Dots", "Bars", "Pulse", "Classic"
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Keys {
    pub quit: String,
    pub install: String,
    pub remove: String,
    pub search_edit: String,
    pub toggle_select: String,
    pub tab_next: String,
    pub tab_prev: String,
    pub system_upgrade: String,
    pub refresh_db: String,
    pub help: String,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
pub struct Theme {
    pub border_color: String,
    pub highlight_color: String,
    pub success_color: String,
    pub error_color: String,
    pub text_primary: String,
    pub text_secondary: String,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Config {
    pub aur_helper: String,
    pub settings: Settings,
    pub keys: Keys,
    pub theme: Theme,
    pub theme_name: String,
    pub custom_theme: Option<Theme>,
}

impl Default for Config {
    fn default() -> Self {
        Self {
            aur_helper: "yay".to_string(),
            settings: Settings {
                search_debounce_ms: 200,
                auto_update_check: true,
                auto_cleanup: false,
                default_tab: "Search".to_string(),
                max_search_results: 50,
                enabled_managers: vec!["pacman".to_string(), "yay".to_string(), "brew".to_string(), "apt".to_string()],
                border_style: "Rounded".to_string(),
                spinner_type: "Dots".to_string(),
            },
            keys: Keys {
                quit: "q".to_string(),
                install: "i".to_string(),
                remove: "x".to_string(),
                search_edit: "e".to_string(),
                toggle_select: " ".to_string(),
                tab_next: "Tab".to_string(),
                tab_prev: "BackTab".to_string(),
                system_upgrade: "U".to_string(),
                refresh_db: "R".to_string(),
                help: "?".to_string(),
            },
            theme: Theme {
                border_color: "blue".to_string(),
                highlight_color: "yellow".to_string(),
                success_color: "green".to_string(),
                error_color: "red".to_string(),
                text_primary: "white".to_string(),
                text_secondary: "cyan".to_string(),
            },
            theme_name: "Default".to_string(),
            custom_theme: None,
        }
    }
}

impl Config {
    pub fn load() -> Self {
        if let Some(proj_dirs) = ProjectDirs::from("", "", "trx") {
            let config_dir = proj_dirs.config_dir();
            let config_path = config_dir.join("config.toml");

            if config_path.exists() {
                if let Ok(content) = fs::read_to_string(config_path) {
                    if let Ok(config) = toml::from_str(&content) {
                        return config;
                    }
                }
            } else {
                // Create default config
                let _ = fs::create_dir_all(config_dir);
                let _ = fs::write(&config_path, toml::to_string(&Self::default()).unwrap());
            }
        }
        Self::default()
    }

    pub fn save(&self) -> Result<(), Box<dyn std::error::Error>> {
        if let Some(proj_dirs) = ProjectDirs::from("", "", "trx") {
            let config_dir = proj_dirs.config_dir();
            let config_path = config_dir.join("config.toml");
            fs::create_dir_all(config_dir)?;
            let content = toml::to_string(self)?;
            fs::write(config_path, content)?;
        }
        Ok(())
    }

    pub fn get_color(&self, color_name: &str) -> Color {
        if color_name.starts_with('#') && color_name.len() == 7 {
            let r = u8::from_str_radix(&color_name[1..3], 16).unwrap_or(0);
            let g = u8::from_str_radix(&color_name[3..5], 16).unwrap_or(0);
            let b = u8::from_str_radix(&color_name[5..7], 16).unwrap_or(0);
            return Color::Rgb(r, g, b);
        }

        match color_name.to_lowercase().as_str() {
            "black" => Color::Black,
            "red" => Color::Red,
            "green" => Color::Green,
            "yellow" => Color::Yellow,
            "blue" => Color::Blue,
            "magenta" => Color::Magenta,
            "cyan" => Color::Cyan,
            "gray" => Color::Gray,
            "dark_gray" => Color::DarkGray,
            "light_red" => Color::LightRed,
            "light_green" => Color::LightGreen,
            "light_yellow" => Color::LightYellow,
            "light_blue" => Color::LightBlue,
            "light_magenta" => Color::LightMagenta,
            "light_cyan" => Color::LightCyan,
            "white" => Color::White,
            _ => Color::Reset,
        }
    }

    pub fn current_theme(&self) -> Theme {
        if self.theme_name == "Custom" {
            if let Some(ref custom) = self.custom_theme {
                return custom.clone();
            }
        }
        
        match self.theme_name.as_str() {
            "Nord" => Theme {
                border_color: "#81A1C1".to_string(),
                highlight_color: "#88C0D0".to_string(),
                success_color: "#A3BE8C".to_string(),
                error_color: "#BF616A".to_string(),
                text_primary: "#ECEFF4".to_string(),
                text_secondary: "#D8DEE9".to_string(),
            },
            "Dracula" => Theme {
                border_color: "#6272a4".to_string(),
                highlight_color: "#ff79c6".to_string(),
                success_color: "#50fa7b".to_string(),
                error_color: "#ff5555".to_string(),
                text_primary: "#f8f8f2".to_string(),
                text_secondary: "#bd93f9".to_string(),
            },
            "OneDark" => Theme {
                border_color: "#61afef".to_string(),
                highlight_color: "#c678dd".to_string(),
                success_color: "#98c379".to_string(),
                error_color: "#e06c75".to_string(),
                text_primary: "#abb2bf".to_string(),
                text_secondary: "#d19a66".to_string(),
            },
            "Gruvbox" => Theme {
                border_color: "#fabd2f".to_string(),
                highlight_color: "#83a598".to_string(),
                success_color: "#b8bb26".to_string(),
                error_color: "#fb4934".to_string(),
                text_primary: "#ebdbb2".to_string(),
                text_secondary: "#d5c4a1".to_string(),
            },
            "Solarized" => Theme {
                border_color: "#268bd2".to_string(),
                highlight_color: "#d33682".to_string(),
                success_color: "#859900".to_string(),
                error_color: "#dc322f".to_string(),
                text_primary: "#93a1a1".to_string(),
                text_secondary: "#839496".to_string(),
            },
            _ => self.theme.clone(),
        }
    }
}