"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ContractInfoV1 = exports.ContractInfoV0 = exports.DisjointContractInfo = exports.SingleContractInfo = exports.ContractInfo = void 0;
const bufio_1 = require("@node-dlc/bufio");
const MessageType_1 = require("../MessageType");
const ContractDescriptor_1 = require("./ContractDescriptor");
const DlcMessage_1 = require("./DlcMessage");
const OracleInfo_1 = require("./OracleInfo");
class ContractInfo extends DlcMessage_1.DlcMessage {
    static deserialize(buf) {
        const reader = new bufio_1.BufferReader(buf);
        const typeId = Number(reader.readBigSize());
        switch (typeId) {
            case MessageType_1.ContractInfoType.Single:
                return SingleContractInfo.deserialize(buf);
            case MessageType_1.ContractInfoType.Disjoint:
                return DisjointContractInfo.deserialize(buf);
            default:
                throw new Error(`Contract info type must be Single (0) or Disjoint (1), got ${typeId}`);
        }
    }
    /**
     * Creates a ContractInfo from JSON data (e.g., from test vectors)
     * @param json JSON object representing contract info
     */
    // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
    static fromJSON(json) {
        if (!json) {
            throw new Error('contractInfo is required');
        }
        // Check if it's a single contract info or disjoint contract info
        if (json.singleContractInfo || json.single_contract_info) {
            return SingleContractInfo.fromJSON(json.singleContractInfo || json.single_contract_info);
        }
        else if (json.disjointContractInfo || json.disjoint_contract_info) {
            return DisjointContractInfo.fromJSON(json.disjointContractInfo || json.disjoint_contract_info);
        }
        else {
            throw new Error('contractInfo must have either singleContractInfo or disjointContractInfo');
        }
    }
    // Method to get total collateral (for compatibility)
    getTotalCollateral() {
        return this.totalCollateral;
    }
}
exports.ContractInfo = ContractInfo;
/**
 * SingleContractInfo contains information about a contract's outcomes,
 * their corresponding payouts, and the oracles to be used.
 * This corresponds to the previous ContractInfoV0.
 */
class SingleContractInfo extends ContractInfo {
    constructor() {
        super(...arguments);
        /**
         * The type for single_contract_info message - using MessageType for IDlcMessage compatibility
         */
        this.type = MessageType_1.MessageType.SingleContractInfo;
        /**
         * The contract info type for new format
         */
        this.contractInfoType = MessageType_1.ContractInfoType.Single;
    }
    /**
     * Creates a SingleContractInfo from JSON data
     * @param json JSON object representing single contract info
     */
    // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
    static fromJSON(json) {
        const instance = new SingleContractInfo();
        instance.totalCollateral = BigInt(json.totalCollateral || json.total_collateral || 0);
        // Handle nested contractInfo structure (test vectors have double nesting)
        const contractInfoData = json.contractInfo || json.contract_info || json;
        // Parse contract descriptor using proper fromJSON method
        instance.contractDescriptor = ContractDescriptor_1.ContractDescriptor.fromJSON(contractInfoData.contractDescriptor ||
            contractInfoData.contract_descriptor);
        // Parse oracle info using proper fromJSON method
        instance.oracleInfo = OracleInfo_1.OracleInfo.fromJSON(contractInfoData.oracleInfo || contractInfoData.oracle_info);
        return instance;
    }
    /**
     * Deserializes a single_contract_info message
     * @param buf
     */
    static deserialize(buf) {
        const instance = new SingleContractInfo();
        const reader = new bufio_1.BufferReader(buf);
        reader.readBigSize(); // read type (0)
        instance.totalCollateral = reader.readUInt64BE();
        // Read contract descriptor as sibling type (starts with its own type prefix)
        instance.contractDescriptor = ContractDescriptor_1.ContractDescriptor.deserialize(Buffer.from(reader.buffer.subarray(reader.position)));
        // Skip past the contract descriptor we just read
        const descLength = instance.contractDescriptor.serialize().length;
        reader.position += descLength;
        // Read oracle info with rust-dlc format - discriminator + body
        const oracleType = Number(reader.readBigSize());
        if (oracleType === 0) {
            // Single oracle
            instance.oracleInfo = OracleInfo_1.SingleOracleInfo.deserializeBody(Buffer.from(reader.buffer.subarray(reader.position)));
        }
        else if (oracleType === 1) {
            // Multi oracle
            instance.oracleInfo = OracleInfo_1.MultiOracleInfo.deserializeBody(Buffer.from(reader.buffer.subarray(reader.position)));
        }
        else {
            throw new Error(`Unknown oracle info type: ${oracleType}`);
        }
        return instance;
    }
    // Compatibility property
    get length() {
        return BigInt(this.serialize().length);
    }
    /**
     * Validates correctness of all fields in the message
     * @throws Will throw an error if validation fails
     */
    validate() {
        if (this.totalCollateral <= 0) {
            throw new Error('totalCollateral must be greater than 0');
        }
        this.oracleInfo.validate();
        // TODO: Add contract descriptor validation once available
        // this.contractDescriptor.validate();
    }
    /**
     * Converts single_contract_info to JSON
     */
    toJSON() {
        // Return enum variant format for Rust compatibility
        return {
            singleContractInfo: {
                totalCollateral: Number(this.totalCollateral),
                contractInfo: {
                    contractDescriptor: this.contractDescriptor.toJSON(),
                    oracleInfo: this.oracleInfo.toJSON(),
                },
            },
        };
    }
    /**
     * Serializes the single_contract_info message into a Buffer
     */
    serialize() {
        const writer = new bufio_1.BufferWriter();
        writer.writeBigSize(this.contractInfoType);
        writer.writeUInt64BE(this.totalCollateral);
        writer.writeBytes(this.contractDescriptor.serialize());
        // Use serializeBody() to match rust-dlc behavior - don't add extra TLV wrapper
        if (this.oracleInfo instanceof OracleInfo_1.SingleOracleInfo) {
            writer.writeBigSize(0); // Single oracle discriminator
            writer.writeBytes(this.oracleInfo.serializeBody());
        }
        else {
            writer.writeBigSize(1); // Multi oracle discriminator
            writer.writeBytes(this.oracleInfo.serializeBody());
        }
        return writer.toBuffer();
    }
}
exports.SingleContractInfo = SingleContractInfo;
SingleContractInfo.contractInfoType = MessageType_1.ContractInfoType.Single;
SingleContractInfo.type = MessageType_1.MessageType.SingleContractInfo;
/**
 * DisjointContractInfo contains information about multiple disjoint contract events.
 * This corresponds to the previous ContractInfoV1.
 */
class DisjointContractInfo extends ContractInfo {
    constructor() {
        super(...arguments);
        /**
         * The type for disjoint_contract_info message - using MessageType for IDlcMessage compatibility
         */
        this.type = MessageType_1.MessageType.DisjointContractInfo;
        /**
         * The contract info type for new format
         */
        this.contractInfoType = MessageType_1.ContractInfoType.Disjoint;
        this.contractOraclePairs = [];
    }
    /**
     * Creates a DisjointContractInfo from JSON data
     * @param json JSON object representing disjoint contract info
     */
    // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
    static fromJSON(json) {
        const instance = new DisjointContractInfo();
        instance.totalCollateral = BigInt(json.totalCollateral || json.total_collateral || 0);
        // Parse contract infos array
        const contractInfosData = json.contractInfos || json.contract_infos || [];
        instance.contractOraclePairs = contractInfosData.map(
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        (contractInfoData) => ({
            contractDescriptor: ContractDescriptor_1.ContractDescriptor.fromJSON(contractInfoData.contractDescriptor ||
                contractInfoData.contract_descriptor),
            oracleInfo: OracleInfo_1.OracleInfo.fromJSON(contractInfoData.oracleInfo || contractInfoData.oracle_info),
        }));
        return instance;
    }
    /**
     * Deserializes a disjoint_contract_info message
     * @param buf
     */
    static deserialize(buf) {
        const instance = new DisjointContractInfo();
        const reader = new bufio_1.BufferReader(buf);
        reader.readBigSize(); // read type (1)
        instance.totalCollateral = reader.readUInt64BE();
        const numDisjointEvents = Number(reader.readBigSize());
        for (let i = 0; i < numDisjointEvents; i++) {
            // Read contract descriptor as sibling type (starts with its own type prefix)
            const contractDescriptor = ContractDescriptor_1.ContractDescriptor.deserialize(Buffer.from(reader.buffer.subarray(reader.position)));
            // Skip past the contract descriptor we just read
            const descLength = contractDescriptor.serialize().length;
            reader.position += descLength;
            // Read oracle info with rust-dlc format - discriminator + body (same as SingleContractInfo)
            const oracleType = Number(reader.readBigSize());
            let oracleInfo;
            if (oracleType === 0) {
                // Single oracle
                oracleInfo = OracleInfo_1.SingleOracleInfo.deserializeBody(Buffer.from(reader.buffer.subarray(reader.position)));
            }
            else if (oracleType === 1) {
                // Multi oracle
                oracleInfo = OracleInfo_1.MultiOracleInfo.deserializeBody(Buffer.from(reader.buffer.subarray(reader.position)));
            }
            else {
                throw new Error(`Unknown oracle info type: ${oracleType}`);
            }
            // Skip past the oracle info we just read
            const oracleInfoLength = oracleInfo.serializeBody().length;
            reader.position += oracleInfoLength;
            instance.contractOraclePairs.push({ contractDescriptor, oracleInfo });
        }
        return instance;
    }
    // Compatibility property
    get length() {
        return BigInt(this.serialize().length);
    }
    /**
     * Validates correctness of all fields in the message
     * @throws Will throw an error if validation fails
     */
    validate() {
        if (this.totalCollateral <= 0) {
            throw new Error('totalCollateral must be greater than 0');
        }
        if (this.contractOraclePairs.length === 0) {
            throw new Error('contractOraclePairs cannot be empty');
        }
        this.contractOraclePairs.forEach((pair, index) => {
            try {
                pair.oracleInfo.validate();
                // TODO: Add contract descriptor validation once available
                // pair.contractDescriptor.validate();
            }
            catch (error) {
                throw new Error(`Validation failed for contract oracle pair ${index}: ${error.message}`);
            }
        });
    }
    /**
     * Converts disjoint_contract_info to JSON
     */
    toJSON() {
        // Return enum variant format for Rust compatibility
        return {
            disjointContractInfo: {
                totalCollateral: Number(this.totalCollateral),
                contractInfos: this.contractOraclePairs.map((pair) => ({
                    contractDescriptor: pair.contractDescriptor.toJSON(),
                    oracleInfo: pair.oracleInfo.toJSON(),
                })),
            },
        };
    }
    /**
     * Serializes the disjoint_contract_info message into a Buffer
     */
    serialize() {
        const writer = new bufio_1.BufferWriter();
        writer.writeBigSize(this.contractInfoType);
        writer.writeUInt64BE(this.totalCollateral);
        writer.writeBigSize(this.contractOraclePairs.length);
        for (const pair of this.contractOraclePairs) {
            writer.writeBytes(pair.contractDescriptor.serialize());
            // Write oracle info with discriminator like SingleContractInfo does
            if (pair.oracleInfo instanceof OracleInfo_1.SingleOracleInfo) {
                writer.writeBigSize(0); // Single oracle discriminator
                writer.writeBytes(pair.oracleInfo.serializeBody());
            }
            else {
                writer.writeBigSize(1); // Multi oracle discriminator
                writer.writeBytes(pair.oracleInfo.serializeBody());
            }
        }
        return writer.toBuffer();
    }
}
exports.DisjointContractInfo = DisjointContractInfo;
DisjointContractInfo.contractInfoType = MessageType_1.ContractInfoType.Disjoint;
DisjointContractInfo.type = MessageType_1.MessageType.DisjointContractInfo;
// Legacy support - keeping old class names as aliases (both value and type exports)
exports.ContractInfoV0 = SingleContractInfo;
exports.ContractInfoV1 = DisjointContractInfo;
//# sourceMappingURL=ContractInfo.js.map