import { Buff } from '@cmdcode/buff';
import { P2TR } from '@scrow/tapscript/address';
import { taproot } from '@scrow/tapscript/sighash';
import { parse_script } from '@scrow/tapscript/script';
import { tap_pubkey } from '@scrow/tapscript/tapkey';
import { combine_psigs } from '@cmdcode/musig2';
import { create_prevout, parse_sequence, create_tx, encode_tx, parse_tx, parse_txid, decode_tx, create_sequence, create_vout } from '@scrow/tapscript/tx';
import * as assert from '../assert.js';
export function create_timelock(duration) {
    return create_sequence('stamp', duration);
}
export function get_address(tapkey, network) {
    if (network === 'mutiny') {
        network = 'signet';
    }
    return P2TR.encode(tapkey, network);
}
export function get_tapkey(pubkey, script) {
    return tap_pubkey(pubkey, { script });
}
export function get_parent_txid(txdata, index = 0) {
    const tx = parse_tx(txdata);
    return tx.vin[index].txid;
}
export function create_txspend(txin) {
    const { txid, vout, prevout } = txin;
    assert.exists(prevout);
    const { value, scriptpubkey } = prevout;
    return { txid, vout, value, scriptkey: scriptpubkey };
}
export function prevout_to_txspend(txinput) {
    const { txid, vout, prevout } = txinput;
    const { value, scriptPubKey } = prevout;
    const script = parse_script(scriptPubKey).hex;
    return { txid, vout, value: Number(value), scriptkey: script };
}
export function parse_txout(deposit) {
    const { txid, vout, value, scriptkey } = deposit;
    return { txid, vout, value, scriptkey };
}
export function create_txinput(txout) {
    const { txid, vout, value, scriptkey } = txout;
    const prevout = { value, scriptPubKey: scriptkey };
    return create_prevout({ txid, vout, prevout });
}
export function parse_txinput(deposit) {
    const { txid, vout, value, scriptkey } = deposit;
    const prevout = { value, scriptPubKey: scriptkey };
    return create_prevout({ txid, vout, prevout });
}
export function parse_timelock(sequence) {
    const sdata = parse_sequence(sequence);
    const timelock = sdata.stamp;
    assert.ok(sdata.enabled, 'Timelock is not enabled.');
    assert.ok(sdata.type === 'stamp', 'Lock type is not a timelock.');
    assert.exists(timelock);
    return timelock;
}
export function parse_prevout(txdata, tapkey) {
    txdata = parse_tx(txdata);
    const vout = txdata.vout.findIndex(txout => {
        const { type, key } = parse_script(txout.scriptPubKey);
        return (type === 'p2tr' &&
            key !== undefined &&
            Buff.is_equal(key, tapkey));
    });
    if (vout !== -1) {
        const txid = parse_txid(txdata);
        const prevout = txdata.vout[vout];
        return create_prevout({ txid, vout, prevout });
    }
    else {
        return null;
    }
}
export function get_signed_tx(ctx, psigs, txdata) {
    const signature = combine_psigs(ctx, psigs);
    txdata.vin[0].witness = [signature];
    taproot.verify_tx(txdata, { txindex: 0 });
    return encode_tx(txdata);
}
export function create_tx_template(script, value) {
    const txout = create_vout({ value, scriptPubKey: script });
    return create_txhex([txout]);
}
export function create_txhex(vout) {
    const txdata = create_tx({ vout });
    return encode_tx(txdata).hex;
}
export function create_sighash(txinput, txbytes) {
    const txdata = decode_tx(txbytes, false);
    return taproot.hash_tx(txdata, { sigflag: 0x81, txinput }).hex;
}
export function get_sighash(path_name, outputs, txinput) {
    const output = outputs.find(e => e[0] === path_name);
    if (output === undefined) {
        throw new Error('Unable to find spending path:' + path_name);
    }
    return create_sighash(txinput, output[1]);
}
export function get_sighashes(outputs, txinput) {
    return outputs.map(([label, vout]) => {
        return [label, create_sighash(txinput, vout)];
    });
}
export function sign_tx(signer, txdata, config) {
    const { sigflag = 0x00 } = config ?? {};
    const hash = taproot.hash_tx(txdata, config);
    const sig = signer.sign(hash);
    return (sigflag === 0x00)
        ? sig
        : Buff.join([sig, sigflag]).hex;
}
