// 导入 clap 库的相关宏和特质，用于构建命令行界面
use clap::{Parser, Subcommand, ValueEnum};
use std::path::PathBuf;

/// ls-plus 的主要命令行接口结构体
///
/// 这个结构体定义了所有可用的命令行选项和参数。
/// 使用 clap 的 derive 宏来自动生成参数解析代码。
#[derive(Parser)]
#[command(name = "ls-plus")] // 程序名称
#[command(about = "Enhanced ls command with modern features")] // 程序描述
#[command(version)] // 自动从 Cargo.toml 获取版本信息
pub struct Cli {
    /// 要列出的目录路径
    /// 如果不指定，默认为当前目录 "."
    #[arg(default_value = ".")]
    pub path: PathBuf,

    /// 显示所有文件（包括隐藏文件）
    /// 对应传统 ls 命令的 -a 选项
    #[arg(short = 'a', long)]
    pub all: bool,

    /// 使用长格式列表显示
    /// 显示详细信息如权限、大小、修改时间等
    /// 对应传统 ls 命令的 -l 选项
    #[arg(short = 'l', long)]
    pub long: bool,

    /// 以人类可读的格式显示文件大小
    /// 例如：1K, 2M, 3G 而不是字节数
    #[arg(long)]
    pub human_readable: bool,

    /// 按修改时间排序文件
    /// 对应传统 ls 命令的 -t 选项
    #[arg(short = 't', long)]
    pub time: bool,

    /// 反向排序
    /// 对应传统 ls 命令的 -r 选项
    #[arg(short = 'r', long)]
    pub reverse: bool,

    /// 目录优先显示
    /// 在文件之前先显示所有目录
    #[arg(long)]
    pub directories_first: bool,

    /// 跟踪符号链接
    /// 显示符号链接指向的实际文件信息，而不是链接本身
    /// 对应传统 ls 命令的 -L 选项
    #[arg(short = 'L', long)]
    pub follow_links: bool,

    /// 显示文件图标
    /// 为不同类型的文件显示相应的 emoji 图标
    #[arg(long)]
    pub icons: bool,

    /// 颜色输出控制
    /// 可选值：always（总是）、never（从不）、auto（自动检测终端）
    #[arg(long, value_enum, default_value_t = ColorOption::Auto)]
    pub color: ColorOption,

    /// 输出格式
    /// 支持多种显示格式：默认、长格式、树形、网格、JSON
    #[arg(long, value_enum, default_value_t = FormatOption::Default)]
    pub format: FormatOption,

    /// 按文件类型过滤
    /// 只显示指定类型的文件，如：file、dir、image 等
    #[arg(long, value_enum)]
    pub file_type: Option<FileTypeFilter>,

    /// 递归列表的最大深度
    /// 限制递归遍历目录的深度
    #[arg(long)]
    pub max_depth: Option<usize>,

    /// 显示 Git 状态
    /// 为每个文件显示其在 Git 仓库中的状态
    #[arg(long)]
    pub git: bool,

    /// 子命令
    /// 支持的子命令包括：config、tree、find、describe
    #[command(subcommand)]
    pub command: Option<Commands>,
}

/// 应用程序支持的子命令枚举
///
/// 每个子命令都有自己的参数和选项，提供不同的功能。
#[derive(Subcommand)]
pub enum Commands {
    /// 配置管理子命令
    /// 用于查看、设置、重置和编辑应用程序配置
    Config {
        /// 配置操作的具体动作
        #[command(subcommand)]
        action: ConfigAction,
    },

    /// 树形视图子命令  
    /// 以层次结构显示目录内容，类似于 tree 命令
    Tree {
        /// 要显示为树形结构的目录路径
        #[arg(default_value = ".")]
        path: PathBuf,

        /// 显示的最大深度
        /// 限制树形视图的层级数量
        #[arg(short = 'd', long)]
        max_depth: Option<usize>,

        /// 显示隐藏文件
        /// 在树形视图中包含以 . 开头的隐藏文件
        #[arg(short = 'a', long)]
        all: bool,
    },

    /// 文件搜索子命令
    /// 根据指定模式搜索匹配的文件
    Find {
        /// 搜索模式
        /// 用于匹配文件名的模式字符串
        pattern: String,

        /// 搜索的目录路径
        #[arg(default_value = ".")]
        path: PathBuf,

        /// 忽略大小写进行搜索
        /// 搜索时不区分大小写
        #[arg(short = 'i', long)]
        ignore_case: bool,

        /// 按文件类型搜索
        /// 只搜索指定类型的文件
        #[arg(short = 't', long, value_enum)]
        file_type: Option<FileTypeFilter>,
    },

    /// 目录描述管理子命令
    /// 允许为目录添加、查看、删除自定义描述信息
    Describe {
        /// 描述操作的具体动作
        #[command(subcommand)]
        action: DescribeAction,
    },
}

/// 配置管理的具体操作枚举
/// 定义了所有可用的配置管理命令
#[derive(Subcommand)]
pub enum ConfigAction {
    /// 显示当前配置
    /// 输出当前的配置文件内容
    Show,

    /// 设置配置值
    /// 修改指定配置项的值
    Set {
        /// 配置键名
        /// 例如："display.show_icons" 或 "behavior.git_integration"
        key: String,
        /// 配置值
        /// 对应键名的新值
        value: String,
    },

    /// 重置配置为默认值
    /// 将所有配置项恢复到初始默认状态
    Reset,

    /// 编辑配置文件
    /// 使用系统默认编辑器打开配置文件进行编辑
    Edit,
}

/// 目录描述管理的具体操作枚举
/// 定义了目录描述功能的所有可用操作
#[derive(Subcommand)]
pub enum DescribeAction {
    /// 为目录添加或更新描述
    /// 如果目录已有描述则更新，否则新增
    Set {
        /// 描述文本内容
        /// 用于描述目录用途或内容的文本
        description: String,
        /// 目录路径
        #[arg(default_value = ".")]
        path: PathBuf,
    },

    /// 显示目录的描述信息
    /// 查看指定目录的描述内容和元信息
    Get {
        /// 目录路径
        #[arg(default_value = ".")]
        path: PathBuf,
    },

    /// 删除目录的描述信息
    /// 从数据库中移除指定目录的描述
    Remove {
        /// 目录路径
        #[arg(default_value = ".")]
        path: PathBuf,
    },

    /// 列出所有目录描述
    /// 显示数据库中所有已保存的目录描述
    List,

    /// 按内容搜索描述
    /// 在所有描述中搜索包含指定关键词的条目
    Search {
        /// 搜索查询字符串
        /// 用于匹配描述内容或路径的关键词
        query: String,
    },

    /// 清理不存在目录的描述
    /// 删除数据库中对应目录已不存在的描述记录
    Cleanup,
}

/// 颜色输出控制选项
/// 定义了终端颜色输出的三种模式
///
/// 这个枚举同时实现了 Serialize 和 Deserialize 特质，
/// 以便在配置文件中保存和读取设置。
#[derive(Clone, Debug, ValueEnum, serde::Serialize, serde::Deserialize)]
pub enum ColorOption {
    /// 始终使用颜色
    /// 无论输出到任何地方都使用颜色
    Always,

    /// 从不使用颜色
    /// 禁用所有颜色输出，仅输出纯文本
    Never,

    /// 自动检测是否使用颜色
    /// 当输出到终端（TTY）时使用颜色，输出到文件时不使用颜色
    Auto,
}

/// 输出格式选项
/// 定义了支持的各种输出显示格式
///
/// 这个枚举允许用户选择不同的显示方式来查看文件列表。
#[derive(Clone, Debug, ValueEnum, serde::Serialize, serde::Deserialize)]
pub enum FormatOption {
    /// 默认格式
    /// 类似于传统 ls 命令的标准输出格式
    Default,

    /// 长格式，显示详细信息
    /// 显示文件权限、大小、修改时间等详细信息，类似 ls -l
    Long,

    /// 树形格式
    /// 以层次结构显示目录内容，类似 tree 命令
    Tree,

    /// 网格格式
    /// 在多列中排列显示文件，充分利用终端宽度
    Grid,

    /// JSON 格式输出
    /// 以 JSON 格式输出文件信息，便于程序化处理
    Json,
}

/// 文件类型过滤器
/// 定义了可用于过滤文件的各种类型
///
/// 允许用户只显示特定类型的文件，例如只显示图片或只显示目录。
#[derive(Clone, Debug, ValueEnum)]
pub enum FileTypeFilter {
    /// 普通文件
    /// 过滤出所有的正常文件（不包括目录和符号链接）
    File,

    /// 目录
    /// 只显示目录，不显示文件
    Dir,

    /// 符号链接
    /// 只显示符号链接文件
    Link,

    /// 可执行文件
    /// 过滤出可执行的文件（基于文件扩展名或权限）
    Exec,

    /// 图像文件
    /// 过滤出常见的图像格式文件（jpg, png, gif 等）
    Image,

    /// 音频文件
    /// 过滤出常见的音频格式文件（mp3, wav, flac 等）
    Audio,

    /// 视频文件
    /// 过滤出常见的视频格式文件（mp4, avi, mkv 等）
    Video,

    /// 压缩档案文件
    /// 过滤出常见的压缩文件（zip, tar, gz 等）
    Archive,

    /// 文档文件
    /// 过滤出常见的文档格式文件（pdf, doc, txt 等）
    Document,
}

/// 为 ColorOption 实现 Default trait
/// 默认使用自动检测颜色模式，这是最常用和合理的选择
impl Default for ColorOption {
    fn default() -> Self {
        ColorOption::Auto
    }
}

/// 为 FormatOption 实现 Default trait  
/// 默认使用标准显示格式，与传统的 ls 命令保持一致
impl Default for FormatOption {
    fn default() -> Self {
        FormatOption::Default
    }
}
