"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createOffer = createOffer;
exports.createOfferBatch = createOfferBatch;
exports.reserveRange = reserveRange;
exports.voidOffer = voidOffer;
exports.voidOfferBatch = voidOfferBatch;
exports.voidNonListedOffer = voidNonListedOffer;
exports.voidNonListedOfferBatch = voidNonListedOfferBatch;
exports.extendOffer = extendOffer;
exports.extendOfferBatch = extendOfferBatch;
exports.updateOfferRoyaltyRecipients = updateOfferRoyaltyRecipients;
exports.updateOfferRoyaltyRecipientsBatch = updateOfferRoyaltyRecipientsBatch;
exports.getOfferHash = getOfferHash;
const common_1 = require("@bosonprotocol/common");
const interface_1 = require("./interface");
const subgraph_1 = require("./subgraph");
const storage_1 = require("./storage");
const storeMetadataItems_1 = require("../metadata/storeMetadataItems");
const subgraph_2 = require("../accounts/subgraph");
// Implementation
function createOffer(args) {
    return __awaiter(this, void 0, void 0, function* () {
        common_1.utils.validation.createOfferArgsSchema.validateSync(args.offerToCreate, {
            abortEarly: false
        });
        const { disputeResolverId, exchangeToken } = args.offerToCreate;
        const disputeResolver = yield (0, subgraph_2.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}"`);
        }
        yield (0, storage_1.storeMetadataOnTheGraph)({
            metadataUriOrHash: args.offerToCreate.metadataUri,
            metadataStorage: args.metadataStorage,
            theGraphStorage: args.theGraphStorage
        });
        yield (0, storeMetadataItems_1.storeMetadataItems)(Object.assign(Object.assign({}, args), { createOffersArgs: [args.offerToCreate] }));
        const transactionRequest = Object.assign(Object.assign({}, args.txRequest), { to: args.contractAddress, data: (0, interface_1.encodeCreateOffer)(args.offerToCreate) });
        if (args.returnTxInfo) {
            return transactionRequest;
        }
        else {
            const txResponse = yield args.web3Lib.sendTransaction(transactionRequest);
            return txResponse;
        }
    });
}
// Implementation
function createOfferBatch(args) {
    return __awaiter(this, void 0, void 0, function* () {
        for (const offerToCreate of args.offersToCreate) {
            common_1.utils.validation.createOfferArgsSchema.validateSync(offerToCreate, {
                abortEarly: false
            });
        }
        yield Promise.all(args.offersToCreate.map((offerToCreate) => (0, storage_1.storeMetadataOnTheGraph)({
            metadataUriOrHash: offerToCreate.metadataUri,
            metadataStorage: args.metadataStorage,
            theGraphStorage: args.theGraphStorage
        })));
        yield (0, storeMetadataItems_1.storeMetadataItems)(Object.assign(Object.assign({}, args), { createOffersArgs: args.offersToCreate }));
        const transactionRequest = {
            to: args.contractAddress,
            data: (0, interface_1.encodeCreateOfferBatch)(args.offersToCreate)
        };
        if (args.returnTxInfo) {
            return transactionRequest;
        }
        else {
            return args.web3Lib.sendTransaction(transactionRequest);
        }
    });
}
// Implementation
function reserveRange(args) {
    return __awaiter(this, void 0, void 0, function* () {
        const offerFromSubgraph = yield (0, subgraph_1.getOfferById)(args.subgraphUrl, args.offerId);
        const signerAddress = yield args.web3Lib.getSignerAddress();
        checkIfOfferReservable(args.offerId, args.length, signerAddress, offerFromSubgraph);
        const transactionRequest = {
            to: args.contractAddress,
            data: (0, interface_1.encodeReserveRange)(args.offerId, args.length, args.to)
        };
        if (args.returnTxInfo) {
            return transactionRequest;
        }
        else {
            return args.web3Lib.sendTransaction(transactionRequest);
        }
    });
}
// Implementation
function voidOffer(args) {
    return __awaiter(this, void 0, void 0, function* () {
        const offerFromSubgraph = yield (0, subgraph_1.getOfferById)(args.subgraphUrl, args.offerId);
        const signerAddress = yield args.web3Lib.getSignerAddress();
        checkIfOfferVoidable(args.offerId, signerAddress, offerFromSubgraph);
        const transactionRequest = {
            to: args.contractAddress,
            data: interface_1.bosonOfferHandlerIface.encodeFunctionData("voidOffer", [args.offerId])
        };
        if (args.returnTxInfo) {
            return transactionRequest;
        }
        else {
            return args.web3Lib.sendTransaction(transactionRequest);
        }
    });
}
// Implementation
function voidOfferBatch(args) {
    return __awaiter(this, void 0, void 0, function* () {
        const offersFromSubgraph = yield (0, subgraph_1.getOffers)(args.subgraphUrl, {
            offersFilter: {
                id_in: args.offerIds.map(String)
            }
        });
        const signerAddress = yield 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: interface_1.bosonOfferHandlerIface.encodeFunctionData("voidOfferBatch", [
                args.offerIds
            ])
        };
        if (args.returnTxInfo) {
            return transactionRequest;
        }
        else {
            return args.web3Lib.sendTransaction(transactionRequest);
        }
    });
}
// Implementation
function voidNonListedOffer(args) {
    return __awaiter(this, void 0, void 0, function* () {
        const transactionRequest = {
            to: args.contractAddress,
            data: (0, interface_1.encodeVoidNonListedOffer)(args.fullOffer)
        };
        if (args.returnTxInfo) {
            return transactionRequest;
        }
        else {
            return args.web3Lib.sendTransaction(transactionRequest);
        }
    });
}
// Implementation
function voidNonListedOfferBatch(args) {
    return __awaiter(this, void 0, void 0, function* () {
        const transactionRequest = {
            to: args.contractAddress,
            data: (0, interface_1.encodeVoidNonListedOfferBatch)(args.fullOffers)
        };
        if (args.returnTxInfo) {
            return transactionRequest;
        }
        else {
            return args.web3Lib.sendTransaction(transactionRequest);
        }
    });
}
// Implementation
function extendOffer(args) {
    return __awaiter(this, void 0, void 0, function* () {
        const transactionRequest = {
            to: args.contractAddress,
            data: interface_1.bosonOfferHandlerIface.encodeFunctionData("extendOffer", [
                args.offerId,
                args.validUntil
            ])
        };
        if (args.returnTxInfo) {
            return transactionRequest;
        }
        else {
            return args.web3Lib.sendTransaction(transactionRequest);
        }
    });
}
// Implementation
function extendOfferBatch(args) {
    return __awaiter(this, void 0, void 0, function* () {
        const transactionRequest = {
            to: args.contractAddress,
            data: interface_1.bosonOfferHandlerIface.encodeFunctionData("extendOfferBatch", [
                args.offerIds,
                args.validUntil
            ])
        };
        if (args.returnTxInfo) {
            return transactionRequest;
        }
        else {
            return args.web3Lib.sendTransaction(transactionRequest);
        }
    });
}
// Implementation
function updateOfferRoyaltyRecipients(args) {
    return __awaiter(this, void 0, void 0, function* () {
        const transactionRequest = {
            to: args.contractAddress,
            data: (0, interface_1.encodeUpdateOfferRoyaltyRecipients)(args)
        };
        if (args.returnTxInfo) {
            return transactionRequest;
        }
        else {
            return args.web3Lib.sendTransaction(transactionRequest);
        }
    });
}
// Implementation
function updateOfferRoyaltyRecipientsBatch(args) {
    return __awaiter(this, void 0, void 0, function* () {
        const transactionRequest = {
            to: args.contractAddress,
            data: (0, interface_1.encodeUpdateOfferRoyaltyRecipientsBatch)(args)
        };
        if (args.returnTxInfo) {
            return transactionRequest;
        }
        else {
            return args.web3Lib.sendTransaction(transactionRequest);
        }
    });
}
function checkIfOfferVoidable(offerId, signerAddress, offerFromSubgraph) {
    var _a, _b;
    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 === common_1.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 === common_1.OfferCreator.Buyer &&
        ((_a = offerFromSubgraph.buyer) === null || _a === void 0 ? void 0 : _a.wallet.toLowerCase()) !==
            signerAddress.toLowerCase()) {
        throw new Error(`Signer with address "${signerAddress}" is not the creator's wallet "${(_b = offerFromSubgraph.buyer) === null || _b === void 0 ? void 0 : _b.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`);
    }
}
function getOfferHash(args) {
    return __awaiter(this, void 0, void 0, function* () {
        const result = yield args.web3Lib.call({
            to: args.contractAddress,
            data: (0, interface_1.encodeGetOfferHash)(args.fullOfferArgsUnsigned)
        });
        return (0, interface_1.decodeGetOfferHash)(result);
    });
}
//# sourceMappingURL=handler.js.map