//! Combine OpenPGP shards and output the hex-encoded secret.

use std::{
    env,
    fs::File,
    path::{Path, PathBuf},
    process::ExitCode,
};

use keyfork_prompt::default_handler;
use keyfork_shard::{openpgp::OpenPGP, Format};

type Result<T, E = Box<dyn std::error::Error>> = std::result::Result<T, E>;

fn validate(
    shard: impl AsRef<Path>,
    key_discovery: Option<&str>,
) -> Result<(File, Option<PathBuf>)> {
    let key_discovery = key_discovery.map(PathBuf::from);
    key_discovery.as_ref().map(std::fs::metadata).transpose()?;

    Ok((File::open(shard)?, key_discovery))
}

fn run() -> Result<()> {
    let mut args = env::args();
    let program_name = args.next().expect("program name");
    let args = args.collect::<Vec<_>>();
    let (messages_file, key_discovery) = match args.as_slice() {
        [shard, key_discovery] => validate(shard, Some(key_discovery))?,
        [shard] => validate(shard, None)?,
        _ => panic!("Usage: {program_name} <shard> [key_discovery]"),
    };

    let openpgp = OpenPGP;
    let prompt_handler = default_handler()?;

    let bytes = openpgp.decrypt_all_shards_to_secret(key_discovery.as_deref(), messages_file, prompt_handler)?;
    print!("{}", smex::encode(bytes));

    Ok(())
}

fn main() -> ExitCode {
    let result = run();
    if let Err(e) = result {
        eprintln!("Error: {e}");
        let mut source = e.source();
        while let Some(new_error) = source.take() {
            eprintln!("Source: {new_error}");
            source = new_error.source();
        }
        return ExitCode::FAILURE;
    }
    ExitCode::SUCCESS
}