use clap::{Parser, Subcommand};

// 构建命令行工具的结构体
/// cvrf2cusa 是一个用于将 CVRF（Common Vulnerability Reporting Framework）格式的安全报告转换为
/// CUSA（CULinux Security Advisory）的工具，其输入格式为 Xml ，输出格式则为 Json。
#[derive(Clone, Debug, Parser)]
#[command(author, version, about, long_about = None)]
pub struct Cli {
    #[clap(subcommand)]
    pub subcommand: CliSub,
}

#[derive(Subcommand, Debug, Clone)]
pub enum CliSub {
    /// CVRF 转换输出子命令
    Convert(ConvertCli),

    /// 创建并生成新的 CUSA 数据文件
    Db(SaDbCli),

    /// CUVAS 定制化自动操作，通过读取配置文件中指定的源、目标目录，执行 CUVARS
    /// 数据库更新操作，配置文件为 `/etc/cuvars/cvrf2cusa.json`
    Auto(AutoCli),
}

/// ConvertCli 用于将指定的 cvrf 格式 xml 文件转换为 cusa 格式
#[derive(Clone, Debug, Parser)]
#[command(author, version, about, long_about = None)]
pub struct ConvertCli {
    /// 输入的文件，应为 cvrf 格式的 xml
    #[arg(short, long)]
    pub input: String,

    /// 可选项，将 cvrf 转换为 cusa 后输出到对应的文件中，格式为 json
    #[arg(short, long)]
    pub output: Option<String>,

    /// 是否在终端打印转换后的 cusa 内容，若不指定输出文件，则输出至终端，
    /// 在指定 output 后同时使用该选项，亦可同时输出至文件和终端
    #[arg(short, long, default_value_t = false)]
    pub print: bool,
}

impl ConvertCli {
    pub fn new(input: String, output: Option<String>, print: bool) -> Self {
        ConvertCli {
            input,
            output,
            print,
        }
    }
}

#[derive(Clone, Debug, Parser)]
#[command(author, version, about, long_about = None)]
pub struct SaDbCli {
    /// 指定一个目录，递归读取其内部的 cvrf 格式的 xml 文件，并最终生成新的 SADB
    #[arg(short, long)]
    pub from: String,

    /// 输出的 sa db 文件，默认为当前路径下的 sainfos
    #[arg(long, default_value_t = String::from("cvrf_sainfos.json"))]
    pub sa: String,

    /// 输出的 cve db 文件，默认为当前路径下的 cves
    #[arg(long, default_value_t = String::from("cvrf_cves.json"))]
    pub cve: String,
}

// 从命令行环境变量读取并转换为 `Cli`
pub fn parse() -> Cli {
    Cli::parse()
}

#[derive(Clone, Debug, Parser)]
#[command(author, version, about, long_about = None)]
pub struct AutoCli {
    /// 指定 CVRF 公告所在的源路径
    #[arg(long, short)]
    pub source: Option<String>,

    /// 转换 CUSA 后存储的目标路径
    #[arg(long, short)]
    pub target: Option<String>,
}
