"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FundingInput = void 0;
const bitcoin_1 = require("@node-dlc/bitcoin");
const bufio_1 = require("@node-dlc/bufio");
const MessageType_1 = require("../MessageType");
const util_1 = require("../util");
const DlcInput_1 = require("./DlcInput");
/**
 * FundingInput contains information about a specific input to be used
 * in a funding transaction, as well as its corresponding on-chain UTXO.
 * Matches rust-dlc FundingInput struct.
 */
class FundingInput {
    constructor() {
        /**
         * The type for funding_input message. funding_input = 42772
         */
        this.type = FundingInput.type;
    }
    /**
     * Creates a FundingInput from JSON data (e.g., from test vectors)
     * @param json JSON object representing funding input
     */
    // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
    static fromJSON(json) {
        const instance = new FundingInput();
        instance.inputSerialId = (0, util_1.toBigInt)(json.inputSerialId || json.input_serial_id);
        // Parse previous transaction
        const prevTxHex = json.prevTx || json.prev_tx;
        if (prevTxHex) {
            instance.prevTx = bitcoin_1.Tx.decode(bufio_1.StreamReader.fromBuffer(Buffer.from(prevTxHex, 'hex')));
        }
        else {
            // Create a minimal transaction for test purposes
            // TODO: This should be properly implemented when full test vector support is needed
            const writer = new bufio_1.BufferWriter();
            writer.writeUInt32BE(2); // version
            writer.writeUInt8(0); // input count
            writer.writeUInt8(1); // output count
            writer.writeUInt64BE(BigInt(100000000)); // output value
            writer.writeUInt8(25); // script length
            writer.writeBytes(Buffer.alloc(25)); // script
            writer.writeUInt32BE(0); // locktime
            const txBytes = writer.toBuffer();
            instance.prevTx = bitcoin_1.Tx.decode(bufio_1.StreamReader.fromBuffer(txBytes));
        }
        instance.prevTxVout = json.prevTxVout || json.prev_tx_vout || 0;
        instance.sequence = new bitcoin_1.Sequence(json.sequence || 0xffffffff);
        instance.maxWitnessLen = json.maxWitnessLen || json.max_witness_len || 108;
        const redeemScript = json.redeemScript || json.redeem_script || '';
        instance.redeemScript = Buffer.from(redeemScript, 'hex');
        // Parse optional DLC input
        const dlcInput = json.dlcInput || json.dlc_input;
        if (dlcInput) {
            instance.dlcInput = DlcInput_1.DlcInput.fromJSON(dlcInput);
        }
        return instance;
    }
    /**
     * Deserializes a funding_input message
     * @param buf
     */
    static deserialize(buf) {
        const instance = new FundingInput();
        const reader = new bufio_1.BufferReader(buf);
        reader.readBigSize(); // read type
        instance.length = reader.readBigSize();
        instance.inputSerialId = reader.readUInt64BE();
        const prevTxLen = reader.readUInt16BE();
        instance.prevTx = bitcoin_1.Tx.decode(bufio_1.StreamReader.fromBuffer(reader.readBytes(prevTxLen)));
        instance.prevTxVout = reader.readUInt32BE();
        instance.sequence = new bitcoin_1.Sequence(reader.readUInt32BE());
        instance.maxWitnessLen = reader.readUInt16BE();
        const redeemScriptLen = reader.readUInt16BE();
        instance.redeemScript = reader.readBytes(redeemScriptLen);
        // Read optional DLC input using rust-dlc Optional format (0x00/0x01 prefix)
        if (reader.position < reader.buffer.length) {
            const dlcInputData = reader.readOptional();
            if (dlcInputData) {
                instance.dlcInput = DlcInput_1.DlcInput.deserializeBody(dlcInputData);
            }
        }
        return instance;
    }
    /**
     * Deserializes a funding_input message without TLV wrapper (for use in DlcOffer)
     * This matches rust-dlc behavior where FundingInput is in a vector without individual TLV wrappers
     * @param buf
     */
    static deserializeBody(buf) {
        const instance = new FundingInput();
        const reader = new bufio_1.BufferReader(buf);
        // No TLV type/length to read - funding input body is serialized directly
        instance.inputSerialId = reader.readUInt64BE();
        // Read prev_tx with BigSize length (to match rust-dlc)
        const prevTxLen = Number(reader.readBigSize());
        instance.prevTx = bitcoin_1.Tx.decode(bufio_1.StreamReader.fromBuffer(reader.readBytes(prevTxLen)));
        instance.prevTxVout = reader.readUInt32BE();
        instance.sequence = new bitcoin_1.Sequence(reader.readUInt32BE());
        instance.maxWitnessLen = reader.readUInt16BE();
        // Test: Read redeem_script with simple u16 length (to match rust-bitcoin ScriptBuf)
        const redeemScriptLen = reader.readUInt16BE();
        instance.redeemScript = reader.readBytes(redeemScriptLen);
        // Read optional DLC input using rust-dlc Optional format (0x00/0x01 prefix)
        if (reader.position < reader.buffer.length) {
            const dlcInputData = reader.readOptional();
            if (dlcInputData) {
                instance.dlcInput = DlcInput_1.DlcInput.deserializeBody(dlcInputData);
            }
        }
        return instance;
    }
    scriptSigLength() {
        if (this.redeemScript.length > 0) {
            return 1 + this.redeemScript.length;
        }
        else {
            return 0;
        }
    }
    /**
     * Validates correctness of all fields
     * @throws Will throw an error if validation fails
     */
    validate() {
        // 1. Type is set automatically in class
        // 2. Ensure the output being spent is a segwit output (P2WPKH or P2WSH)
        // Note: We check the output script type, not whether prevTx was created with segwit inputs.
        // This allows spending UTXOs from transactions that used legacy inputs but have segwit outputs.
        const output = this.prevTx.outputs[this.prevTxVout];
        if (!output) {
            throw new Error(`fundingInput prevTxVout ${this.prevTxVout} does not exist in prevTx`);
        }
        const scriptPubKey = output.scriptPubKey.serializeCmds();
        // P2WPKH: OP_0 <20-byte-key-hash> = 0x0014{20 bytes} = 22 bytes total
        // P2WSH:  OP_0 <32-byte-script-hash> = 0x0020{32 bytes} = 34 bytes total
        // P2TR:   OP_1 <32-byte-pubkey> = 0x5120{32 bytes} = 34 bytes total
        const isP2WPKH = scriptPubKey.length === 22 &&
            scriptPubKey[0] === 0x00 &&
            scriptPubKey[1] === 0x14;
        const isP2WSH = scriptPubKey.length === 34 &&
            scriptPubKey[0] === 0x00 &&
            scriptPubKey[1] === 0x20;
        const isP2TR = scriptPubKey.length === 34 &&
            scriptPubKey[0] === 0x51 &&
            scriptPubKey[1] === 0x20;
        if (!isP2WPKH && !isP2WSH && !isP2TR) {
            throw new Error('fundingInput must spend a segwit output (P2WPKH, P2WSH, or P2TR)');
        }
    }
    /**
     * Converts funding_input to JSON (canonical rust-dlc format)
     */
    toJSON() {
        const result = {
            inputSerialId: (0, util_1.bigIntToNumber)(this.inputSerialId),
            prevTx: this.prevTx.serialize().toString('hex'),
            prevTxVout: this.prevTxVout,
            sequence: this.sequence.value,
            maxWitnessLen: this.maxWitnessLen,
            redeemScript: this.redeemScript.toString('hex'),
        };
        if (this.dlcInput) {
            result.dlcInput = this.dlcInput.toJSON();
        }
        return result;
    }
    /**
     * Serializes the funding_input message into a Buffer
     */
    serialize() {
        const writer = new bufio_1.BufferWriter();
        writer.writeBigSize(this.type);
        const dataWriter = new bufio_1.BufferWriter();
        dataWriter.writeUInt64BE(this.inputSerialId);
        dataWriter.writeUInt16BE(this.prevTx.serialize().length);
        dataWriter.writeBytes(this.prevTx.serialize());
        dataWriter.writeUInt32BE(this.prevTxVout);
        dataWriter.writeUInt32BE(this.sequence.value);
        dataWriter.writeUInt16BE(this.maxWitnessLen);
        dataWriter.writeUInt16BE(this.redeemScript.length);
        dataWriter.writeBytes(this.redeemScript);
        // Write optional DLC input using rust-dlc Optional format (0x00/0x01 prefix)
        const dlcInputData = this.dlcInput ? this.dlcInput.serializeBody() : null;
        dataWriter.writeOptional(dlcInputData);
        writer.writeBigSize(dataWriter.size);
        writer.writeBytes(dataWriter.toBuffer());
        return writer.toBuffer();
    }
    serializeBody() {
        // Serialize funding input body without TLV wrapper (for embedding in DlcOffer)
        // This matches rust-dlc behavior where FundingInput.write() doesn't add type_id
        const writer = new bufio_1.BufferWriter();
        writer.writeUInt64BE(this.inputSerialId);
        // Use BigSize for prev_tx length to match rust-dlc (prev_tx, vec)
        writer.writeBigSize(this.prevTx.serialize().length);
        writer.writeBytes(this.prevTx.serialize());
        writer.writeUInt32BE(this.prevTxVout);
        writer.writeUInt32BE(this.sequence.value);
        writer.writeUInt16BE(this.maxWitnessLen);
        // Test: Use simple u16 length for redeem_script to match rust-bitcoin ScriptBuf
        writer.writeUInt16BE(this.redeemScript.length);
        writer.writeBytes(this.redeemScript);
        // Write optional DLC input using rust-dlc Optional format (0x00/0x01 prefix)
        const dlcInputData = this.dlcInput ? this.dlcInput.serializeBody() : null;
        writer.writeOptional(dlcInputData);
        return writer.toBuffer();
    }
}
exports.FundingInput = FundingInput;
FundingInput.type = MessageType_1.MessageType.FundingInput;
//# sourceMappingURL=FundingInput.js.map