// 导入依赖项
use crate::cli::{ColorOption, ConfigAction, FormatOption}; // CLI 相关的枚举类型
use crate::error::{LsPlusError, Result}; // 错误处理类型
use dirs; // 系统目录路径获取
use serde::{Deserialize, Serialize}; // 序列化和反序列化支持
use std::fs; // 文件系统操作
use std::path::PathBuf; // 路径处理

/// 应用程序的主配置结构体
///
/// 这个结构体包含了应用程序的所有配置选项，分为四个主要类别：
/// - display: 显示相关的配置
/// - behavior: 行为相关的配置  
/// - icons: 图标相关的配置
/// - colors: 颜色相关的配置
///
/// 使用 serde 的 Serialize 和 Deserialize 特质来支持从 TOML 文件读取和写入配置。
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Config {
    /// 显示相关的配置选项
    pub display: DisplayConfig,
    /// 行为相关的配置选项
    pub behavior: BehaviorConfig,
    /// 图标相关的配置选项
    pub icons: IconConfig,
    /// 颜色相关的配置选项
    pub colors: ColorConfig,
}

/// 显示相关的配置选项
///
/// 包含所有与文件列表显示相关的配置，
/// 如格式、颜色、图标等。
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DisplayConfig {
    /// 默认的输出格式
    /// 可选值：default, long, tree, grid, json
    pub default_format: FormatOption,

    /// 颜色模式
    /// 控制何时使用颜色输出
    pub color_mode: ColorOption,

    /// 是否显示文件图标
    /// 为不同类型的文件显示 emoji 图标
    pub show_icons: bool,

    /// 是否使用人类可读的文件大小
    /// 例如：1K, 2M, 3G 而不是字节数
    pub human_readable_sizes: bool,

    /// 是否目录优先显示
    /// 在文件之前先显示所有目录
    pub directories_first: bool,

    /// 是否显示隐藏文件
    /// 默认是否显示以 . 开头的隐藏文件
    pub show_hidden: bool,
}

/// 行为相关的配置选项
///
/// 包含所有与应用程序行为相关的配置，
/// 如排序、深度限制、Git 集成等。
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BehaviorConfig {
    /// 是否跟踪符号链接
    /// 当为 true 时，显示符号链接指向的实际文件信息
    pub follow_symlinks: bool,

    /// 是否启用 Git 集成
    /// 为文件显示 Git 仓库状态信息
    pub git_integration: bool,

    /// 递归遍历的最大深度
    /// None 表示无限制，Some(n) 表示最大 n 层
    pub max_depth: Option<usize>,

    /// 是否按修改时间排序
    /// 默认按文件名排序，设为 true 则按修改时间排序
    pub sort_by_time: bool,

    /// 是否反向排序
    /// 默认从小到大排序，设为 true 则从大到小排序
    pub reverse_sort: bool,
}

/// 图标相关的配置选项
///
/// 控制文件图标的显示和主题。
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IconConfig {
    /// 是否启用图标显示
    /// 为不同类型的文件显示相应的 emoji 图标
    pub enable_icons: bool,

    /// 图标主题
    /// 目前支持 "default" 主题，未来可能支持更多主题
    pub icon_theme: String,
}

/// 颜色相关的配置选项
///
/// 细化控制不同类型信息的颜色显示。
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ColorConfig {
    /// 是否为文件名使用颜色
    /// 根据文件类型显示不同颜色（目录、文件、可执行文件等）
    pub file_colors: bool,

    /// 是否为文件大小使用颜色
    /// 根据文件大小范围显示不同颜色
    pub size_colors: bool,

    /// 是否为时间信息使用颜色
    /// 为修改时间显示颜色
    pub time_colors: bool,

    /// 是否为权限信息使用颜色
    /// 为文件权限显示颜色
    pub permission_colors: bool,
}

/// 为 Config 实现 Default trait
///
/// 提供合理的默认配置值，这些默认值：
/// - 保持与传统 ls 命令的兼容性
/// - 提供良好的用户体验
/// - 适合大多数使用场景
impl Default for Config {
    fn default() -> Self {
        Self {
            display: DisplayConfig {
                default_format: FormatOption::Default, // 使用标准格式
                color_mode: ColorOption::Auto,         // 自动检测是否使用颜色
                show_icons: false,                     // 默认不显示图标
                human_readable_sizes: true,            // 默认使用人类可读的文件大小
                directories_first: true,               // 默认目录优先显示
                show_hidden: false,                    // 默认不显示隐藏文件
            },
            behavior: BehaviorConfig {
                follow_symlinks: false, // 默认不跟踪符号链接
                git_integration: false, // 默认不启用 Git 集成
                max_depth: None,        // 默认无深度限制
                sort_by_time: false,    // 默认按文件名排序
                reverse_sort: false,    // 默认正向排序
            },
            icons: IconConfig {
                enable_icons: false,               // 默认不启用图标
                icon_theme: "default".to_string(), // 使用默认图标主题
            },
            colors: ColorConfig {
                file_colors: true,       // 默认为文件名使用颜色
                size_colors: true,       // 默认为文件大小使用颜色
                time_colors: true,       // 默认为时间信息使用颜色
                permission_colors: true, // 默认为权限信息使用颜色
            },
        }
    }
}

impl Config {
    /// 获取配置目录路径
    ///
    /// 返回应用程序的配置目录路径：
    /// - Linux/macOS: ~/.config/ls-plus/
    /// - Windows: %APPDATA%/ls-plus/
    ///
    /// # 返回值
    /// * `Result<PathBuf>` - 成功时返回配置目录路径，失败时返回错误
    pub fn config_dir() -> Result<PathBuf> {
        dirs::config_dir()
            .map(|dir| dir.join("ls-plus")) // 在系统配置目录下创建 ls-plus 子目录
            .ok_or_else(|| LsPlusError::system_error("Could not determine config directory"))
    }

    /// 获取配置文件路径
    ///
    /// 返回主配置文件 config.toml 的完整路径。
    ///
    /// # 返回值
    /// * `Result<PathBuf>` - 成功时返回配置文件路径
    pub fn config_file() -> Result<PathBuf> {
        Ok(Self::config_dir()?.join("config.toml"))
    }

    /// 从配置文件加载配置
    ///
    /// 尝试从 config.toml 文件加载配置。如果文件不存在，
    /// 则返回默认配置。
    ///
    /// # 返回值
    /// * `Result<Self>` - 成功时返回加载的配置，失败时返回错误
    ///
    /// # 错误
    /// * 配置文件读取失败
    /// * TOML 格式解析失败
    pub fn load() -> Result<Self> {
        let config_file = Self::config_file()?;

        // 如果配置文件不存在，返回默认配置
        if !config_file.exists() {
            return Ok(Self::default());
        }

        // 读取配置文件内容
        let content = fs::read_to_string(&config_file)
            .map_err(|e| LsPlusError::system_error(format!("Failed to read config file: {e}")))?;

        // 解析 TOML 格式的配置内容
        let config: Config = toml::from_str(&content)
            .map_err(|e| LsPlusError::invalid_config(format!("Invalid config format: {e}")))?;

        Ok(config)
    }

    /// 将配置保存到文件
    ///
    /// 将当前配置序列化为 TOML 格式并写入配置文件。
    /// 如果配置目录不存在，会自动创建。
    ///
    /// # 返回值
    /// * `Result<()>` - 成功时返回空结果，失败时返回错误
    ///
    /// # 错误
    /// * 配置目录创建失败
    /// * 配置序列化失败
    /// * 配置文件写入失败
    pub fn save(&self) -> Result<()> {
        let config_dir = Self::config_dir()?;
        let config_file = Self::config_file()?;

        // 如果配置目录不存在，创建它
        if !config_dir.exists() {
            fs::create_dir_all(&config_dir).map_err(|e| {
                LsPlusError::system_error(format!("Failed to create config directory: {e}"))
            })?;
        }

        // 将配置序列化为格式化的 TOML 字符串
        let content = toml::to_string_pretty(self)
            .map_err(|e| LsPlusError::system_error(format!("Failed to serialize config: {e}")))?;

        // 将内容写入配置文件
        fs::write(&config_file, content)
            .map_err(|e| LsPlusError::system_error(format!("Failed to write config file: {e}")))?;

        Ok(())
    }

    /// 设置配置项的值
    ///
    /// 根据键名设置对应的配置值。支持的键名包括：
    ///
    /// ## 显示配置 (display.*)
    /// - `display.default_format`: 默认显示格式 (default|long|tree|grid|json)
    /// - `display.color_mode`: 颜色模式 (always|never|auto)
    /// - `display.show_icons`: 是否显示图标 (true|false)
    /// - `display.human_readable_sizes`: 是否使用人类可读的文件大小 (true|false)
    /// - `display.directories_first`: 是否目录优先显示 (true|false)
    /// - `display.show_hidden`: 是否显示隐藏文件 (true|false)
    ///
    /// ## 行为配置 (behavior.*)
    /// - `behavior.follow_symlinks`: 是否跟踪符号链接 (true|false)
    /// - `behavior.git_integration`: 是否启用Git集成 (true|false)
    /// - `behavior.sort_by_time`: 是否按时间排序 (true|false)
    /// - `behavior.reverse_sort`: 是否反向排序 (true|false)
    ///
    /// # 参数
    /// * `key` - 配置键名，使用点号分隔的层次结构
    /// * `value` - 配置值的字符串表示
    ///
    /// # 返回值
    /// * `Result<()>` - 成功时返回空结果，失败时返回错误
    ///
    /// # 错误
    /// * 未知的配置键名
    /// * 无效的配置值格式
    /// * 布尔值解析失败
    pub fn set_value(&mut self, key: &str, value: &str) -> Result<()> {
        match key {
            // 显示格式配置
            "display.default_format" => {
                self.display.default_format = match value {
                    "default" => FormatOption::Default, // 标准格式
                    "long" => FormatOption::Long,       // 长格式，显示详细信息
                    "tree" => FormatOption::Tree,       // 树形格式
                    "grid" => FormatOption::Grid,       // 网格格式
                    "json" => FormatOption::Json,       // JSON 格式
                    _ => return Err(LsPlusError::invalid_config("Invalid format option")),
                };
            }
            // 颜色模式配置
            "display.color_mode" => {
                self.display.color_mode = match value {
                    "always" => ColorOption::Always, // 总是使用颜色
                    "never" => ColorOption::Never,   // 从不使用颜色
                    "auto" => ColorOption::Auto,     // 自动检测
                    _ => return Err(LsPlusError::invalid_config("Invalid color option")),
                };
            }
            // 显示图标配置
            "display.show_icons" => {
                self.display.show_icons = value
                    .parse()
                    .map_err(|_| LsPlusError::invalid_config("Invalid boolean value"))?;
            }
            // 人类可读文件大小配置
            "display.human_readable_sizes" => {
                self.display.human_readable_sizes = value
                    .parse()
                    .map_err(|_| LsPlusError::invalid_config("Invalid boolean value"))?;
            }
            // 目录优先显示配置
            "display.directories_first" => {
                self.display.directories_first = value
                    .parse()
                    .map_err(|_| LsPlusError::invalid_config("Invalid boolean value"))?;
            }
            // 显示隐藏文件配置
            "display.show_hidden" => {
                self.display.show_hidden = value
                    .parse()
                    .map_err(|_| LsPlusError::invalid_config("Invalid boolean value"))?;
            }
            // 跟踪符号链接配置
            "behavior.follow_symlinks" => {
                self.behavior.follow_symlinks = value
                    .parse()
                    .map_err(|_| LsPlusError::invalid_config("Invalid boolean value"))?;
            }
            // Git 集成配置
            "behavior.git_integration" => {
                self.behavior.git_integration = value
                    .parse()
                    .map_err(|_| LsPlusError::invalid_config("Invalid boolean value"))?;
            }
            // 按时间排序配置
            "behavior.sort_by_time" => {
                self.behavior.sort_by_time = value
                    .parse()
                    .map_err(|_| LsPlusError::invalid_config("Invalid boolean value"))?;
            }
            // 反向排序配置
            "behavior.reverse_sort" => {
                self.behavior.reverse_sort = value
                    .parse()
                    .map_err(|_| LsPlusError::invalid_config("Invalid boolean value"))?;
            }
            // 未知的配置键名
            _ => {
                return Err(LsPlusError::invalid_config(format!(
                    "Unknown config key: {key}"
                )))
            }
        }
        Ok(())
    }
}

/// 处理配置相关的命令
///
/// 这个函数是配置管理的主入口点，根据传入的动作执行相应的配置操作。
///
/// # 参数
/// * `action` - 要执行的配置动作（显示、设置、重置、编辑）
///
/// # 返回值
/// * `Result<()>` - 成功时返回空结果，失败时返回错误
///
/// # 支持的操作
/// - `Show`: 显示当前配置内容
/// - `Set`: 设置指定配置项的值
/// - `Reset`: 重置所有配置为默认值
/// - `Edit`: 使用系统编辑器打开配置文件
pub async fn handle_config_command(action: ConfigAction) -> Result<()> {
    match action {
        // 显示当前配置
        ConfigAction::Show => {
            let config = Config::load()?;
            // 将配置序列化为格式化的 TOML 字符串
            let config_str = toml::to_string_pretty(&config).map_err(|e| {
                LsPlusError::system_error(format!("Failed to serialize config: {e}"))
            })?;
            println!("{config_str}");
        }
        // 设置配置值
        ConfigAction::Set { key, value } => {
            let mut config = Config::load()?;
            // 设置指定键的值
            config.set_value(&key, &value)?;
            // 保存配置到文件
            config.save()?;
            println!("Configuration updated: {key} = {value}");
        }
        // 重置配置为默认值
        ConfigAction::Reset => {
            let config = Config::default();
            // 保存默认配置到文件，覆盖现有配置
            config.save()?;
            println!("Configuration reset to defaults");
        }
        // 编辑配置文件
        ConfigAction::Edit => {
            let config_file = Config::config_file()?;

            // 如果配置文件不存在，先创建一个包含默认值的配置文件
            if !config_file.exists() {
                let default_config = Config::default();
                default_config.save()?;
            }

            // 尝试使用系统默认编辑器打开配置文件
            // 首先尝试从环境变量 EDITOR 获取编辑器，如果没有则使用 nano
            let editor = std::env::var("EDITOR").unwrap_or_else(|_| "nano".to_string());
            let status = std::process::Command::new(&editor)
                .arg(&config_file)
                .status()
                .map_err(|e| LsPlusError::system_error(format!("Failed to open editor: {e}")))?;

            // 检查编辑器是否成功退出
            if !status.success() {
                return Err(LsPlusError::system_error("Editor exited with error"));
            }
        }
    }
    Ok(())
}
