use super::args::VerifyArgs;

use crate::errors::KamError;
use base64::engine::Engine as _;
use base64::engine::general_purpose::STANDARD as BASE64_ENGINE;
use openssl::hash::MessageDigest;
use openssl::pkey::PKey;
use openssl::sign::Verifier;
use std::fs;
use std::path::Path;
use std::path::PathBuf;

struct VerificationInput {
    src_path: PathBuf,
    data: Vec<u8>,
    sig_bytes: Vec<u8>,
}

/// AUTO-GENERATED BY Kam/scripts/add_missing_docs.py: placeholder documentation for public function 'run'. Replace with real documentation. (2025-12-30T22:23:21Z)
///
/// # Errors
/// Returns `KamError` if source/signature files are missing, public key cannot be loaded, certificate verification fails, or signature verification fails.
pub fn run(args: &VerifyArgs) -> Result<(), KamError> {
    let input = load_verification_input(args)?;
    let pkey = load_public_key(args)?;

    if args.verbose {
        use crate::utils::Utils;
        Utils::executing(&trf!("verify.calculating_hash", input.src_path.display()));
    }

    let result = verify_signature(&input.data, &input.sig_bytes, &pkey, args.verbose)?;
    print_verification_result(result, &input.src_path, args.verbose)
}

fn load_verification_input(args: &VerifyArgs) -> Result<VerificationInput, KamError> {
    let src_str = args.src.as_ref().ok_or_else(|| {
        KamError::CommandFailed("Source file is required for verification".to_string())
    })?;
    let src_path = Path::new(src_str);

    if !src_path.exists() {
        return Err(KamError::CommandFailed(trf!(
            "Source file not found: {}",
            src_path.display()
        )));
    }

    // 如果没有指定签名文件，就用源文件名+.sig
    let sig_path = args.sig.as_ref().map_or_else(
        || Path::new(&format!("{src_str}.sig")).to_path_buf(),
        |s| Path::new(s).to_path_buf(),
    );

    if !sig_path.exists() {
        return Err(KamError::CommandFailed(trf!(
            "Signature file not found: {}",
            sig_path.display()
        )));
    }

    // 2. 读取源文件和签名
    let data = fs::read(src_path).map_err(KamError::Io)?;
    let sig_b64 = fs::read_to_string(&sig_path).map_err(KamError::Io)?;
    // 签名是base64编码的，需要解码
    let sig_bytes = BASE64_ENGINE
        .decode(sig_b64.trim().as_bytes())
        .map_err(|e| KamError::CommandFailed(trf!("Failed to base64 decode signature: {}", e)))?;

    Ok(VerificationInput {
        src_path: src_path.to_path_buf(),
        data,
        sig_bytes,
    })
}

fn load_public_key(args: &VerifyArgs) -> Result<PKey<openssl::pkey::Public>, KamError> {
    if let Some(key_path_str) = &args.key {
        return load_public_key_file(Path::new(key_path_str));
    }

    if let Some(cert_chain_path) = &args.cert_chain {
        return load_public_key_from_cert_chain(cert_chain_path, args.verbose);
    }

    if let Some(cert_name) = &args.cert_name {
        return load_public_key_from_cached_cert(cert_name, args.verbose);
    }

    crate::cmds::secret::utils::get_or_refresh_public_key(&args.secret, args.verbose)
        .map_err(|e| KamError::CommandFailed(trf!("Failed to retrieve public key: {}", e)))
}

fn load_public_key_file(key_path: &Path) -> Result<PKey<openssl::pkey::Public>, KamError> {
    let key_bytes = fs::read(key_path).map_err(KamError::Io)?;
    PKey::public_key_from_pem(&key_bytes).map_err(|e| {
        KamError::CommandFailed(trf!(
            "Failed to parse public key PEM from {}: {}",
            key_path.display(),
            e
        ))
    })
}

fn load_public_key_from_cert_chain(
    cert_chain_path: &str,
    verbose: bool,
) -> Result<PKey<openssl::pkey::Public>, KamError> {
    if verbose {
        use crate::utils::Utils;
        Utils::executing(&trf!(
            "verify.loading_certificate_chain_from",
            cert_chain_path
        ));
    }
    let chain_pem = fs::read_to_string(cert_chain_path).map_err(KamError::Io)?;
    verify_chain_and_load_public_key(&chain_pem, verbose)
}

fn load_public_key_from_cached_cert(
    cert_name: &str,
    verbose: bool,
) -> Result<PKey<openssl::pkey::Public>, KamError> {
    if verbose {
        use crate::utils::Utils;
        Utils::executing(&trf!("verify.loading_cached_certificate", cert_name));
    }
    let chain_pem = crate::cmds::secret::cert::load_cert_chain(cert_name)?;
    verify_chain_and_load_public_key(&chain_pem, verbose)
}

fn verify_chain_and_load_public_key(
    chain_pem: &str,
    verbose: bool,
) -> Result<PKey<openssl::pkey::Public>, KamError> {
    let trusted_cas = crate::cmds::secret::cert::load_trusted_cas()?;
    if trusted_cas.is_empty() {
        return Err(KamError::CommandFailed(trf!(
            "secret.no_trusted_root_cas_add_one_with"
        )));
    }

    if verbose {
        use crate::utils::Utils;
        Utils::executing(&trf!("verify.verifying_certificate_chain"));
    }
    let pub_key_pem = crate::cmds::secret::cert::verify_cert_chain(chain_pem, &trusted_cas)?;

    if verbose {
        use crate::utils::Utils;
        Utils::success(&trf!("verify.certificate_chain_verified_successfully"));
    }

    PKey::public_key_from_pem(pub_key_pem.as_bytes()).map_err(|e| {
        KamError::CommandFailed(format!("Failed to parse public key from certificate: {e}"))
    })
}

fn verify_signature(
    data: &[u8],
    sig_bytes: &[u8],
    pkey: &PKey<openssl::pkey::Public>,
    verbose: bool,
) -> Result<bool, KamError> {
    let mut verifier = Verifier::new(MessageDigest::sha256(), pkey)
        .map_err(|e| KamError::CommandFailed(trf!("Failed to create verifier: {}", e)))?;

    if verbose {
        use crate::utils::Utils;
        Utils::executing(crate::i18n::tr("verify.verifying_signature"));
    }
    verifier
        .update(data)
        .map_err(|e| KamError::CommandFailed(trf!("Failed to update verifier: {}", e)))?;

    verifier
        .verify(sig_bytes)
        .map_err(|e| KamError::CommandFailed(trf!("Verification error: {}", e)))
}

fn print_verification_result(result: bool, src_path: &Path, verbose: bool) -> Result<(), KamError> {
    if result {
        use crate::utils::Utils;
        if verbose {
            Utils::success(crate::i18n::tr("Verification successful"));
        } else {
            Utils::success(crate::i18n::tr("Verified"));
        }
        Ok(())
    } else {
        use crate::utils::Utils;
        let fail_msg = trf!("Verification FAILED for '{}'", src_path.display());
        Utils::error(&fail_msg);
        Err(KamError::CommandFailed(fail_msg))
    }
}
