Documentation
use crate::error::Error;
use crate::imports::*;
use crate::result::Result;
use crate::KaspaCli;
use kaspa_bip32::{Language, Mnemonic};
use kaspa_wallet_core::account::{BIP32_ACCOUNT_KIND, LEGACY_ACCOUNT_KIND, MULTISIG_ACCOUNT_KIND};
use std::sync::Arc;

pub async fn prompt_for_mnemonic(term: &Arc<Terminal>) -> Result<Vec<String>> {
    let mut words: Vec<String> = vec![];
    loop {
        if words.is_empty() {
            tprintln!(term, "Please enter mnemonic (12 or 24 space separated words)");
        } else if words.len() < 12 {
            let remains_for_12 = 12 - words.len();
            let remains_for_24 = 24 - words.len();
            tprintln!(term, "Please enter additional {} or {} words or <enter> to abort", remains_for_12, remains_for_24);
        } else {
            let remains_for_24 = 24 - words.len();
            tprintln!(term, "Please enter additional {} words or <enter> to abort", remains_for_24);
        }
        let text = term.ask(false, "Mnemonic:").await?;
        let list = text.split_whitespace().map(|s| s.to_string()).collect::<Vec<String>>();
        if list.is_empty() {
            return Err(Error::UserAbort);
        }
        words.extend(list);

        if words.len() > 24 || words.len() == 12 || words.len() == 24 {
            break;
        }
    }

    if words.len() > 24 {
        Err("Mnemonic must be 12 or 24 words".into())
    } else {
        Ok(words)
    }
}

pub(crate) async fn import_with_mnemonic(ctx: &Arc<KaspaCli>, account_kind: AccountKind, additional_xpubs: &[String]) -> Result<()> {
    let wallet = ctx.wallet();

    if !wallet.is_open() {
        return Err(Error::WalletIsNotOpen);
    }

    let term = ctx.term();

    tprintln!(ctx);
    let wallet_secret = Secret::new(term.ask(true, "Enter wallet password: ").await?.trim().as_bytes().to_vec());
    tprintln!(ctx);
    let mnemonic = prompt_for_mnemonic(&term).await?;
    tprintln!(ctx);
    let length = mnemonic.len();
    match account_kind.as_ref() {
        LEGACY_ACCOUNT_KIND if length != 12 => Err(Error::Custom(format!("wrong mnemonic length ({length})"))),
        BIP32_ACCOUNT_KIND if length != 24 => Err(Error::Custom(format!("wrong mnemonic length ({length})"))),

        LEGACY_ACCOUNT_KIND | BIP32_ACCOUNT_KIND | MULTISIG_ACCOUNT_KIND => Ok(()),
        _ => Err(Error::Custom("unsupported account kind".to_owned())),
    }?;

    let payment_secret = if account_kind == LEGACY_ACCOUNT_KIND {
        None
    } else {
        tpara!(
            ctx,
            "\
            \
            If your original wallet has a bip39 recovery passphrase, please enter it now.\
            \
            Specifically, this is not a wallet password. This is a secondary mnemonic passphrase\
            used to encrypt your mnemonic. This is known as a 'payment passphrase'\
            'mnemonic passphrase', or a 'recovery passphrase'. If your mnemonic was created\
            with a payment passphrase and you do not enter it now, the import process\
            will generate a different private key.\
            \
            If you do not have a bip39 recovery passphrase, press ENTER.\
            \
            ",
        );

        let payment_secret = term.ask(true, "Enter payment password (optional): ").await?;
        if payment_secret.trim().is_empty() {
            None
        } else {
            Some(Secret::new(payment_secret.trim().as_bytes().to_vec()))
        }
    };

    let mnemonic = mnemonic.join(" ");
    let mnemonic = Mnemonic::new(mnemonic.trim(), Language::English)?;

    let account = if account_kind != MULTISIG_ACCOUNT_KIND {
        wallet.import_with_mnemonic(&wallet_secret, payment_secret.as_ref(), mnemonic, account_kind).await?
    } else {
        let mut mnemonics_secrets = vec![(mnemonic, payment_secret)];
        while matches!(
            term.ask(false, "Do you want to add more mnemonics (type 'y' to approve)?: ").await?.trim(),
            "y" | "Y" | "YES" | "yes"
        ) {
            tprintln!(ctx);
            let mnemonic = prompt_for_mnemonic(&term).await?;
            tprintln!(ctx);
            let payment_secret = term.ask(true, "Enter payment password (optional): ").await?;
            let payment_secret = payment_secret.trim().is_not_empty().then(|| Secret::new(payment_secret.trim().as_bytes().to_vec()));
            let mnemonic = mnemonic.join(" ");
            let mnemonic = Mnemonic::new(mnemonic.trim(), Language::English)?;

            mnemonics_secrets.push((mnemonic, payment_secret));
        }

        let mut additional_xpubs = additional_xpubs.to_vec();
        if additional_xpubs.is_empty() {
            loop {
                let xpub_key = term.ask(false, "Enter extended public key: (empty to skip or stop)").await?;
                if xpub_key.is_empty() {
                    break;
                }
                additional_xpubs.push(xpub_key.trim().to_owned());
            }
        }
        let n_required: u16 = term.ask(false, "Enter the minimum number of signatures required: ").await?.parse()?;

        wallet.import_multisig_with_mnemonic(&wallet_secret, mnemonics_secrets, n_required, additional_xpubs).await?
    };

    tprintln!(ctx, "\naccount imported: {}\n", account.get_list_string()?);
    wallet.select(Some(&account)).await?;
    Ok(())
}