//! This CLI tool is experimental, and exposes some functionality that's not available in rsop yet.
//!
//! Its functionality may be considered complementary to rsop, but with a less stable CLI API.
//! Hopefully, some of it will get refined and eventually upstreamed into SOP (and rsop).

use std::path::PathBuf;

use clap::Parser;
use rpgpie::{
    certificate::Checked,
    merge::CertificateInfo,
    model::status_summary,
    util::print_cert,
};

#[derive(Parser, Debug)]
#[command(about = "An experimental OpenPGP CLI tool", version)]
pub struct Cli {
    #[command(subcommand)]
    pub cmd: Command,
}

#[derive(Parser, Debug)]
pub enum Command {
    /// Print a high-level summary of a certificate's status.
    ///
    /// This shows interpreted data and validity information about the certificate's contents.
    /// It filters out invalid signature packets, and shows just one active signature per component.
    ///
    /// This view is useful to inspect which components are valid.
    Status(StatusCommand),

    /// Print the raw internals of a certificate.
    ///
    /// This prints a detailed representation of a certificate's contents, without filtering out
    /// invalid elements.
    ///
    /// (This view is intended for lower level debugging, and inspecting the changes in a
    /// certificate over time.)
    Show(ShowCommand),
}

#[derive(Parser, Debug)]
pub struct ShowCommand {
    #[arg(help = "An OpenPGP file")]
    pub file: Option<PathBuf>,

    #[arg(short, long)]
    pub verbose: bool,

    /// Print objects in the order that they are stored in wire format
    #[arg(short, long)]
    pub unordered: bool,
}

#[derive(Parser, Debug)]
pub struct StatusCommand {
    #[arg(help = "An OpenPGP file")]
    pub file: Option<PathBuf>,

    #[arg(short, long)]
    pub verbose: bool,

    #[arg(long)]
    pub json: bool,
}

fn main() {
    let cli = Cli::parse();

    match cli.cmd {
        Command::Show(show) => {
            let loaded = if let Some(file) = show.file {
                CertificateInfo::from_file(&file)
            } else {
                CertificateInfo::from_reader(std::io::stdin())
            };

            let Ok(CertificateInfo::Cert(cert)) = loaded else {
                unimplemented!("unsupported {:?}", loaded);
            };

            print_cert(&cert, show.verbose, !show.unordered);
        }
        Command::Status(status) => {
            let loaded = if let Some(file) = status.file {
                CertificateInfo::from_file(&file)
            } else {
                CertificateInfo::from_reader(std::io::stdin())
            };

            let Ok(CertificateInfo::Cert(cert)) = loaded else {
                unimplemented!("unsupported {:?}", loaded);
            };

            let checked: Checked = cert.into();
            let summary = status_summary(&checked);

            if !status.json {
                print!("{}", &summary)
            } else {
                let json = serde_json::to_string_pretty(&summary).unwrap();
                println!("{}", json);
            }
        }
    }
}
