import { utils } from "@bosonprotocol/common";
import { formatBytes32String } from "@ethersproject/strings";
import { encodeCreateSeller, encodeUpdateSeller, encodeCreateDisputeResolver, encodeAddFeesToDisputeResolver, encodeAddSellersToAllowList, encodeRemoveFeesFromDisputeResolver, encodeRemoveSellersFromAllowList, encodeUpdateDisputeResolver, encodeOptInToSellerUpdate, encodeOptInToDisputeResolverUpdate, encodeCreateNewCollection, encodeIsSellerSaltAvailable, decodeIsSellerSaltAvailable, encodeCalculateCollectionAddress, decodeCalculateCollectionAddress, encodeAddRoyaltyRecipients, encodeUpdateRoyaltyRecipients, encodeGetRoyaltyRecipients, decodeGetRoyaltyRecipients, encodeRemoveRoyaltyRecipients, encodeCreateBuyer } from "./interface";
import { getDisputeResolverById } from "./subgraph";
import { storeMetadataOnTheGraph } from "../offers/storage";
export const INITIAL_COLLECTION_ID = "initial";
export async function findCollectionSalt(args) {
    // collectionSalt is added to the seller admin address to give the sellerSalt that is used to compute the voucher contract address
    // The seller creation will fail in case sellerSalt already exists
    // This may happen if the admin address was already assigned to another seller in the past
    // In that case, we add a random suffix on the collectionId to generate a different salt
    let collectionSalt = formatBytes32String(INITIAL_COLLECTION_ID);
    const isAvailable = await isSellerSaltAvailable({
        adminAddress: args.sellerToCreate.admin,
        salt: collectionSalt,
        contractAddress: args.contractAddress,
        web3Lib: args.web3Lib
    });
    if (!isAvailable) {
        const uuid = Math.floor(Math.random() * 100000000).toFixed(0);
        collectionSalt = formatBytes32String(`${INITIAL_COLLECTION_ID}-${uuid}`.slice(0, 31));
    }
    return collectionSalt;
}
// Implementation
export async function createSeller(args) {
    const collectionSalt = await findCollectionSalt(args);
    await Promise.all([args.sellerToCreate.contractUri, args.sellerToCreate.metadataUri].map((metadataUri) => storeMetadataOnTheGraph({
        metadataUriOrHash: metadataUri,
        metadataStorage: args.metadataStorage,
        theGraphStorage: args.theGraphStorage
    })));
    const transactionRequest = {
        to: args.contractAddress,
        data: encodeCreateSeller(args.sellerToCreate, collectionSalt)
    };
    if (args.returnTxInfo) {
        return transactionRequest;
    }
    else {
        return args.web3Lib.sendTransaction(transactionRequest);
    }
}
// Implementation
export async function updateSeller(args) {
    await storeMetadataOnTheGraph({
        metadataUriOrHash: args.sellerUpdates.metadataUri,
        metadataStorage: args.metadataStorage,
        theGraphStorage: args.theGraphStorage
    });
    const transactionRequest = {
        to: args.contractAddress,
        data: encodeUpdateSeller(args.sellerUpdates)
    };
    if (args.returnTxInfo) {
        return transactionRequest;
    }
    else {
        return args.web3Lib.sendTransaction(transactionRequest);
    }
}
// Implementation
export async function optInToSellerUpdate(args) {
    const transactionRequest = {
        to: args.contractAddress,
        data: encodeOptInToSellerUpdate(args.sellerUpdates)
    };
    if (args.returnTxInfo) {
        return transactionRequest;
    }
    else {
        return args.web3Lib.sendTransaction(transactionRequest);
    }
}
// Implementation
export async function createBuyer(args) {
    const transactionRequest = {
        to: args.contractAddress,
        data: encodeCreateBuyer(args.buyerToCreate)
    };
    if (args.returnTxInfo) {
        return transactionRequest;
    }
    else {
        return args.web3Lib.sendTransaction(transactionRequest);
    }
}
// Implementation
export async function createDisputeResolver(args) {
    // TODO: validate metadata
    // disputeResolverToCreate.metadataUri
    const transactionRequest = {
        to: args.contractAddress,
        data: encodeCreateDisputeResolver(args.disputeResolverToCreate)
    };
    if (args.returnTxInfo) {
        return transactionRequest;
    }
    else {
        return args.web3Lib.sendTransaction(transactionRequest);
    }
}
// Implementation
export async function addFeesToDisputeResolver(args) {
    const transactionRequest = {
        to: args.contractAddress,
        data: encodeAddFeesToDisputeResolver(args)
    };
    if (args.returnTxInfo) {
        return transactionRequest;
    }
    else {
        return args.web3Lib.sendTransaction(transactionRequest);
    }
}
// Implementation
export async function addSellersToAllowList(args) {
    const transactionRequest = {
        to: args.contractAddress,
        data: encodeAddSellersToAllowList(args)
    };
    if (args.returnTxInfo) {
        return transactionRequest;
    }
    else {
        return args.web3Lib.sendTransaction(transactionRequest);
    }
}
// Implementation
export async function removeFeesFromDisputeResolver(args) {
    const transactionRequest = {
        to: args.contractAddress,
        data: encodeRemoveFeesFromDisputeResolver(args)
    };
    if (args.returnTxInfo) {
        return transactionRequest;
    }
    else {
        return args.web3Lib.sendTransaction(transactionRequest);
    }
}
// Implementation
export async function removeSellersFromAllowList(args) {
    const transactionRequest = {
        to: args.contractAddress,
        data: encodeRemoveSellersFromAllowList(args)
    };
    if (args.returnTxInfo) {
        return transactionRequest;
    }
    else {
        return args.web3Lib.sendTransaction(transactionRequest);
    }
}
// Implementation
export async function updateDisputeResolver(args) {
    const disputeResolver = await getDisputeResolverById(args.subgraphUrl, args.disputeResolverId);
    assertDisputeResolver(args.disputeResolverId, disputeResolver);
    // TODO: validate metadata
    // updates.metadataUri
    const transactionRequest = {
        to: args.contractAddress,
        data: encodeUpdateDisputeResolver({
            ...disputeResolver,
            ...args.updates,
            escalationResponsePeriod: args.updates.escalationResponsePeriodInMS
                ? utils.timestamp.msToSec(args.updates.escalationResponsePeriodInMS)
                : disputeResolver.escalationResponsePeriod
        })
    };
    if (args.returnTxInfo) {
        return transactionRequest;
    }
    else {
        return args.web3Lib.sendTransaction(transactionRequest);
    }
}
// Implementation
export async function optInToDisputeResolverUpdate(args) {
    const transactionRequest = {
        to: args.contractAddress,
        data: encodeOptInToDisputeResolverUpdate(args.disputeResolverUpdates)
    };
    if (args.returnTxInfo) {
        return transactionRequest;
    }
    else {
        return args.web3Lib.sendTransaction(transactionRequest);
    }
}
function assertDisputeResolver(disputeResolverId, disputeResolver) {
    if (!disputeResolver) {
        throw new Error(`Dispute resolver with id ${disputeResolverId} does not exist`);
    }
}
// Implementation
export async function createNewCollection(args) {
    // call calculateCollectionAddress() to check no collection with the same collectionId already exists
    if (args.collectionToCreate.sellerId) {
        const { isAvailable } = await calculateCollectionAddress({
            sellerId: args.collectionToCreate.sellerId,
            collectionId: args.collectionToCreate.collectionId,
            contractAddress: args.contractAddress,
            web3Lib: args.web3Lib
        });
        if (!isAvailable) {
            throw new Error(`CollectionId '${args.collectionToCreate.collectionId}' is not available for seller '${args.collectionToCreate.sellerId}'`);
        }
    }
    await storeMetadataOnTheGraph({
        metadataUriOrHash: args.collectionToCreate.contractUri,
        metadataStorage: args.metadataStorage,
        theGraphStorage: args.theGraphStorage
    });
    const transactionRequest = {
        to: args.contractAddress,
        data: encodeCreateNewCollection(args.collectionToCreate)
    };
    if (args.returnTxInfo) {
        return transactionRequest;
    }
    else {
        return args.web3Lib.sendTransaction(transactionRequest);
    }
}
export async function isSellerSaltAvailable(args) {
    const result = await args.web3Lib.call({
        to: args.contractAddress,
        data: encodeIsSellerSaltAvailable(args.adminAddress, args.salt)
    });
    return decodeIsSellerSaltAvailable(result);
}
export async function calculateCollectionAddress(args) {
    if (args.collectionId.length >= 32) {
        throw new Error(`collectionId length should not exceed 31 characters`);
    }
    const collectionSalt = formatBytes32String(args.collectionId);
    const result = await args.web3Lib.call({
        to: args.contractAddress,
        data: encodeCalculateCollectionAddress(args.sellerId, collectionSalt)
    });
    return decodeCalculateCollectionAddress(result);
}
// Implementation
export async function addRoyaltyRecipients(args) {
    const transactionRequest = {
        to: args.contractAddress,
        data: encodeAddRoyaltyRecipients(args)
    };
    if (args.returnTxInfo) {
        return transactionRequest;
    }
    else {
        return args.web3Lib.sendTransaction(transactionRequest);
    }
}
// Implementation
export async function updateRoyaltyRecipients(args) {
    const transactionRequest = {
        to: args.contractAddress,
        data: encodeUpdateRoyaltyRecipients(args)
    };
    if (args.returnTxInfo) {
        return transactionRequest;
    }
    else {
        return args.web3Lib.sendTransaction(transactionRequest);
    }
}
// Implementation
export async function removeRoyaltyRecipients(args) {
    const transactionRequest = {
        to: args.contractAddress,
        data: encodeRemoveRoyaltyRecipients(args)
    };
    if (args.returnTxInfo) {
        return transactionRequest;
    }
    else {
        return args.web3Lib.sendTransaction(transactionRequest);
    }
}
export async function getRoyaltyRecipients(args) {
    const result = await args.web3Lib.call({
        to: args.contractAddress,
        data: encodeGetRoyaltyRecipients(args)
    });
    return decodeGetRoyaltyRecipients(result);
}
//# sourceMappingURL=handler.js.map