import invariant from "tiny-invariant";
import { ASSEMBLE_MALLEABLE_EXTERNAL_MATCH_ROUTE, RENEGADE_API_KEY_HEADER } from "../constants.js";
import type { AuthConfig } from "../createAuthConfig.js";
import { BaseError, type BaseErrorType } from "../errors/base.js";
import type { ExternalOrder, SponsoredQuoteResponse } from "../types/externalMatch.js";
import { MalleableExternalMatchResponse } from "../types/malleableMatch.js";
import { stringifyForWasm } from "../utils/bigJSON.js";
import { postWithSymmetricKey } from "../utils/http.js";

export type AssembleMalleableQuoteParameters = {
    quote: SponsoredQuoteResponse;
    updatedOrder?: ExternalOrder;
    doGasEstimation?: boolean;
    allowShared?: boolean;
    receiverAddress?: `0x${string}`;
    requestGasSponsorship?: boolean;
    refundAddress?: `0x${string}`;
};

export type AssembleMalleableQuoteReturnType = MalleableExternalMatchResponse;

export type AssembleMalleableQuoteErrorType = BaseErrorType;

export async function assembleMalleableQuote(
    config: AuthConfig,
    parameters: AssembleMalleableQuoteParameters,
): Promise<AssembleMalleableQuoteReturnType> {
    const {
        quote,
        updatedOrder,
        doGasEstimation = false,
        allowShared = false,
        receiverAddress = "",
        requestGasSponsorship,
        refundAddress,
    } = parameters;

    if (requestGasSponsorship !== undefined || refundAddress !== undefined) {
        console.warn(
            "`requestGasSponsorship` and `refundAddress` are deprecated. Request gas sponsorship when requesting the quote.",
        );
    }

    const { apiSecret, apiKey } = config;
    invariant(apiSecret, "API secret not specified in config");
    invariant(apiKey, "API key not specified in config");
    const symmetricKey = config.utils.b64_to_hex_hmac_key(apiSecret);

    const stringifiedQuote = stringifyForWasm(quote);
    const stringifiedOrder = updatedOrder ? stringifyForWasm(updatedOrder) : "";
    const body = config.utils.assemble_external_match(
        doGasEstimation,
        allowShared,
        stringifiedOrder,
        stringifiedQuote,
        receiverAddress,
    );

    const url = config.getBaseUrl(ASSEMBLE_MALLEABLE_EXTERNAL_MATCH_ROUTE);

    const res = await postWithSymmetricKey(config, {
        url,
        body,
        key: symmetricKey,
        headers: {
            [RENEGADE_API_KEY_HEADER]: apiKey,
        },
    });
    if (!res.match_bundle) {
        throw new BaseError("Failed to assemble external quote");
    }
    return new MalleableExternalMatchResponse(
        res.match_bundle,
        res.is_sponsored,
        res.gas_sponsorship_info,
    );
}
