import { utils, OfferCreator } from "@bosonprotocol/common";
import { bosonOfferHandlerIface, decodeGetOfferHash, encodeCreateOffer, encodeCreateOfferBatch, encodeGetOfferHash, encodeReserveRange, encodeUpdateOfferRoyaltyRecipients, encodeUpdateOfferRoyaltyRecipientsBatch, encodeVoidNonListedOffer, encodeVoidNonListedOfferBatch } from "./interface";
import { getOfferById, getOffers } from "./subgraph";
import { storeMetadataOnTheGraph } from "./storage";
import { storeMetadataItems } from "../metadata/storeMetadataItems";
import { getDisputeResolverById } from "../accounts/subgraph";
// Implementation
export async function createOffer(args) {
    utils.validation.createOfferArgsSchema.validateSync(args.offerToCreate, {
        abortEarly: false
    });
    const { disputeResolverId, exchangeToken } = args.offerToCreate;
    const disputeResolver = await getDisputeResolverById(args.subgraphUrl, disputeResolverId);
    if (!disputeResolver) {
        throw new Error(`Dispute resolver with id "${disputeResolverId}" does not exist`);
    }
    if (!disputeResolver.fees.some((fee) => fee.token.address.toLowerCase() === exchangeToken.toLowerCase())) {
        throw new Error(`Dispute resolver with id "${disputeResolverId}" does not support exchange token "${exchangeToken}"`);
    }
    await storeMetadataOnTheGraph({
        metadataUriOrHash: args.offerToCreate.metadataUri,
        metadataStorage: args.metadataStorage,
        theGraphStorage: args.theGraphStorage
    });
    await storeMetadataItems({
        ...args,
        createOffersArgs: [args.offerToCreate]
    });
    const transactionRequest = {
        ...args.txRequest,
        to: args.contractAddress,
        data: encodeCreateOffer(args.offerToCreate)
    };
    if (args.returnTxInfo) {
        return transactionRequest;
    }
    else {
        const txResponse = await args.web3Lib.sendTransaction(transactionRequest);
        return txResponse;
    }
}
// Implementation
export async function createOfferBatch(args) {
    for (const offerToCreate of args.offersToCreate) {
        utils.validation.createOfferArgsSchema.validateSync(offerToCreate, {
            abortEarly: false
        });
    }
    await Promise.all(args.offersToCreate.map((offerToCreate) => storeMetadataOnTheGraph({
        metadataUriOrHash: offerToCreate.metadataUri,
        metadataStorage: args.metadataStorage,
        theGraphStorage: args.theGraphStorage
    })));
    await storeMetadataItems({
        ...args,
        createOffersArgs: args.offersToCreate
    });
    const transactionRequest = {
        to: args.contractAddress,
        data: encodeCreateOfferBatch(args.offersToCreate)
    };
    if (args.returnTxInfo) {
        return transactionRequest;
    }
    else {
        return args.web3Lib.sendTransaction(transactionRequest);
    }
}
// Implementation
export async function reserveRange(args) {
    const offerFromSubgraph = await getOfferById(args.subgraphUrl, args.offerId);
    const signerAddress = await args.web3Lib.getSignerAddress();
    checkIfOfferReservable(args.offerId, args.length, signerAddress, offerFromSubgraph);
    const transactionRequest = {
        to: args.contractAddress,
        data: encodeReserveRange(args.offerId, args.length, args.to)
    };
    if (args.returnTxInfo) {
        return transactionRequest;
    }
    else {
        return args.web3Lib.sendTransaction(transactionRequest);
    }
}
// Implementation
export async function voidOffer(args) {
    const offerFromSubgraph = await getOfferById(args.subgraphUrl, args.offerId);
    const signerAddress = await args.web3Lib.getSignerAddress();
    checkIfOfferVoidable(args.offerId, signerAddress, offerFromSubgraph);
    const transactionRequest = {
        to: args.contractAddress,
        data: bosonOfferHandlerIface.encodeFunctionData("voidOffer", [args.offerId])
    };
    if (args.returnTxInfo) {
        return transactionRequest;
    }
    else {
        return args.web3Lib.sendTransaction(transactionRequest);
    }
}
// Implementation
export async function voidOfferBatch(args) {
    const offersFromSubgraph = await getOffers(args.subgraphUrl, {
        offersFilter: {
            id_in: args.offerIds.map(String)
        }
    });
    const signerAddress = await args.web3Lib.getSignerAddress();
    const invalidOfferIdErrors = [];
    for (const offerId of args.offerIds) {
        const offerFromSubgraph = offersFromSubgraph.find((offer) => offer.id === offerId.toString());
        try {
            checkIfOfferVoidable(offerId, signerAddress, offerFromSubgraph);
        }
        catch (error) {
            invalidOfferIdErrors.push(error);
        }
    }
    if (invalidOfferIdErrors.length) {
        throw new Error(`Some offers can not be voided. ${invalidOfferIdErrors}`);
    }
    const transactionRequest = {
        to: args.contractAddress,
        data: bosonOfferHandlerIface.encodeFunctionData("voidOfferBatch", [
            args.offerIds
        ])
    };
    if (args.returnTxInfo) {
        return transactionRequest;
    }
    else {
        return args.web3Lib.sendTransaction(transactionRequest);
    }
}
// Implementation
export async function voidNonListedOffer(args) {
    const transactionRequest = {
        to: args.contractAddress,
        data: encodeVoidNonListedOffer(args.fullOffer)
    };
    if (args.returnTxInfo) {
        return transactionRequest;
    }
    else {
        return args.web3Lib.sendTransaction(transactionRequest);
    }
}
// Implementation
export async function voidNonListedOfferBatch(args) {
    const transactionRequest = {
        to: args.contractAddress,
        data: encodeVoidNonListedOfferBatch(args.fullOffers)
    };
    if (args.returnTxInfo) {
        return transactionRequest;
    }
    else {
        return args.web3Lib.sendTransaction(transactionRequest);
    }
}
// Implementation
export async function extendOffer(args) {
    const transactionRequest = {
        to: args.contractAddress,
        data: bosonOfferHandlerIface.encodeFunctionData("extendOffer", [
            args.offerId,
            args.validUntil
        ])
    };
    if (args.returnTxInfo) {
        return transactionRequest;
    }
    else {
        return args.web3Lib.sendTransaction(transactionRequest);
    }
}
// Implementation
export async function extendOfferBatch(args) {
    const transactionRequest = {
        to: args.contractAddress,
        data: bosonOfferHandlerIface.encodeFunctionData("extendOfferBatch", [
            args.offerIds,
            args.validUntil
        ])
    };
    if (args.returnTxInfo) {
        return transactionRequest;
    }
    else {
        return args.web3Lib.sendTransaction(transactionRequest);
    }
}
// Implementation
export async function updateOfferRoyaltyRecipients(args) {
    const transactionRequest = {
        to: args.contractAddress,
        data: encodeUpdateOfferRoyaltyRecipients(args)
    };
    if (args.returnTxInfo) {
        return transactionRequest;
    }
    else {
        return args.web3Lib.sendTransaction(transactionRequest);
    }
}
// Implementation
export async function updateOfferRoyaltyRecipientsBatch(args) {
    const transactionRequest = {
        to: args.contractAddress,
        data: encodeUpdateOfferRoyaltyRecipientsBatch(args)
    };
    if (args.returnTxInfo) {
        return transactionRequest;
    }
    else {
        return args.web3Lib.sendTransaction(transactionRequest);
    }
}
function checkIfOfferVoidable(offerId, signerAddress, offerFromSubgraph) {
    if (!offerFromSubgraph) {
        throw new Error(`Offer with id "${offerId}" does not exist`);
    }
    if (offerFromSubgraph.voidedAt) {
        throw new Error(`Offer with id "${offerId}" is already voided`);
    }
    if (offerFromSubgraph.creator === OfferCreator.Seller &&
        offerFromSubgraph.seller.assistant.toLowerCase() !==
            signerAddress.toLowerCase()) {
        throw new Error(`Signer with address "${signerAddress}" is not the assistant "${offerFromSubgraph.seller.assistant}" of offer with id "${offerId}"`);
    }
    if (offerFromSubgraph.creator === OfferCreator.Buyer &&
        offerFromSubgraph.buyer?.wallet.toLowerCase() !==
            signerAddress.toLowerCase()) {
        throw new Error(`Signer with address "${signerAddress}" is not the creator's wallet "${offerFromSubgraph.buyer?.wallet}" of offer with id "${offerId}"`);
    }
}
function checkIfOfferReservable(offerId, length, signerAddress, offerFromSubgraph) {
    checkIfOfferVoidable(offerId, signerAddress, offerFromSubgraph);
    if (!length) {
        throw new Error(`Range length is zero`);
    }
    if (offerFromSubgraph.quantityAvailable < length) {
        throw new Error(`Range length is too large`);
    }
}
export async function getOfferHash(args) {
    const result = await args.web3Lib.call({
        to: args.contractAddress,
        data: encodeGetOfferHash(args.fullOfferArgsUnsigned)
    });
    return decodeGetOfferHash(result);
}
//# sourceMappingURL=handler.js.map