"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Channel = void 0;
const tslib_1 = require("tslib");
const constants_1 = require("../constants");
const viem = require("viem");
const PUSH_CHANNEL = require("../channels");
const config = require("../config");
const helpers_1 = require("../helpers");
const PUSH_PAYLOAD = require("../payloads");
const progressHook_1 = require("../progressHook");
const PushNotificationTypes_1 = require("./PushNotificationTypes");
const alias_1 = require("./alias");
const delegate_1 = require("./delegate");
const pushNotificationBase_1 = require("./pushNotificationBase");
class Channel extends pushNotificationBase_1.PushNotificationBaseClass {
    constructor(signer, env, account) {
        super(signer, env, account);
        /**
         * @description - returns information about a channel
         * @param {string} [options.channel] - channel address in caip, defaults to eth caip address
         * @returns information about the channel if it exists
         */
        this.info = (channel, options) => tslib_1.__awaiter(this, void 0, void 0, function* () {
            try {
                const { raw = true } = options || {};
                this.checkUserAddressExists(channel);
                channel = channel !== null && channel !== void 0 ? channel : (0, helpers_1.getFallbackETHCAIPAddress)(this.env, this.account);
                return yield PUSH_CHANNEL.getChannel({
                    channel: channel,
                    env: this.env,
                    raw: raw,
                });
            }
            catch (error) {
                throw new Error(`Push SDK Error: API : channel::info : ${error}`);
            }
        });
        /**
         * @description - returns relevant information as per the query that was passed
         * @param {string} query - search query
         * @param {number} [options.page] -  page number. default is set to Constants.PAGINATION.INITIAL_PAGE
         * @param {number} [options.limit] - number of feeds per page. default is set to Constants.PAGINATION.LIMIT
         * @returns Array of results relevant to the serach query
         */
        this.search = (query, options) => tslib_1.__awaiter(this, void 0, void 0, function* () {
            try {
                const { page = constants_1.default.PAGINATION.INITIAL_PAGE, limit = constants_1.default.PAGINATION.LIMIT, } = options || {};
                return yield PUSH_CHANNEL.search({
                    query: query,
                    page: page,
                    limit: limit,
                    env: this.env,
                });
            }
            catch (error) {
                throw new Error(`Push SDK Error: API : channel::search : ${error}`);
            }
        });
        /**
         * @description - Get subscribers of a channell
         * @param {string} [options.channel] - channel in caip. defaults to account from signer with eth caip
         * @returns array of subscribers
         */
        this.subscribers = (options) => tslib_1.__awaiter(this, void 0, void 0, function* () {
            var _a, _b;
            try {
                let channel = (options === null || options === void 0 ? void 0 : options.channel)
                    ? options.channel
                    : this.account
                        ? (0, helpers_1.getFallbackETHCAIPAddress)(this.env, this.account)
                        : null;
                this.checkUserAddressExists(channel);
                channel = (0, helpers_1.validateCAIP)(channel)
                    ? channel
                    : (0, helpers_1.getFallbackETHCAIPAddress)(this.env, channel);
                if (options && options.page) {
                    return yield PUSH_CHANNEL.getSubscribers({
                        channel: channel,
                        env: this.env,
                        page: options.page,
                        limit: (_a = options.limit) !== null && _a !== void 0 ? _a : 10,
                        setting: (_b = options.setting) !== null && _b !== void 0 ? _b : false,
                        category: options.category,
                        raw: options.raw,
                    });
                }
                else {
                    /** @dev - Fallback to deprecated method when page is not provided ( to ensure backward compatibility ) */
                    /** @notice - This will be removed in V2 Publish */
                    return yield PUSH_CHANNEL._getSubscribers({
                        channel: channel,
                        env: this.env,
                    });
                }
            }
            catch (error) {
                throw new Error(`Push SDK Error: API : channel::subscribers : ${error}`);
            }
        });
        /**
         *
         * @param {string[]} recipients - Array of recipients. `['0x1'] -> TARGET`, `['0x1, 0x2'] -> SUBSET`, `['*'] -> BROADCAST`
         * @param {object} options - Notification options
         * @returns
         */
        this.send = (recipients, options) => tslib_1.__awaiter(this, void 0, void 0, function* () {
            var _c, _d;
            try {
                this.checkSignerObjectExists();
                const channelInfo = yield this.getChannelOrAliasInfo((_c = options.channel) !== null && _c !== void 0 ? _c : this.account);
                const lowLevelPayload = this.generateNotificationLowLevelPayload({
                    signer: this.signer,
                    env: this.env,
                    recipients: recipients,
                    options: options,
                    channel: (_d = options.channel) !== null && _d !== void 0 ? _d : this.account,
                    channelInfo: channelInfo,
                });
                return yield PUSH_PAYLOAD.sendNotification(lowLevelPayload);
            }
            catch (error) {
                throw new Error(`Push SDK Error: API : channel::send : ${error}`);
            }
        });
        this.create = (options) => tslib_1.__awaiter(this, void 0, void 0, function* () {
            const { name, description, url, icon, alias = null, progressHook, } = options || {};
            try {
                // create push token instance
                let aliasInfo;
                // validate all the parameters and length
                this.validateChannelParameters(options);
                // check for PUSH balance
                const pushTokenContract = yield this.createContractInstance(config.TOKEN[this.env], config.ABIS.TOKEN, config.TOKEN_VIEM_NETWORK_MAP[this.env]);
                const balance = yield this.fetchBalance(pushTokenContract, this.account);
                const fees = viem.parseUnits(config.MIN_TOKEN_BALANCE[this.env].toString(), 18);
                if (fees > balance) {
                    throw new Error('Insufficient PUSH balance');
                }
                // if alias is passed, check for the caip
                if (alias) {
                    if (!(0, helpers_1.validateCAIP)(alias)) {
                        throw new Error('Invalid alias CAIP');
                    }
                    const aliasDetails = (0, helpers_1.getCAIPDetails)(alias);
                    aliasInfo = {
                        [`${aliasDetails === null || aliasDetails === void 0 ? void 0 : aliasDetails.blockchain}:${aliasDetails === null || aliasDetails === void 0 ? void 0 : aliasDetails.networkId}`]: aliasDetails === null || aliasDetails === void 0 ? void 0 : aliasDetails.address,
                    };
                }
                // construct channel identity
                progressHook === null || progressHook === void 0 ? void 0 : progressHook(progressHook_1.default['PUSH-CREATE-01']);
                const input = {
                    name: name,
                    info: description,
                    url: url,
                    icon: icon,
                    aliasDetails: aliasInfo !== null && aliasInfo !== void 0 ? aliasInfo : {},
                };
                const cid = yield this.uploadToIPFSViaPushNode(JSON.stringify(input));
                const allowanceAmount = yield this.fetchAllownace(pushTokenContract, this.account, config.CORE_CONFIG[this.env].EPNS_CORE_CONTRACT);
                if (!(allowanceAmount >= fees)) {
                    progressHook === null || progressHook === void 0 ? void 0 : progressHook(progressHook_1.default['PUSH-CREATE-02']);
                    const approvalRes = yield this.approveToken(pushTokenContract, config.CORE_CONFIG[this.env].EPNS_CORE_CONTRACT, fees);
                    if (!approvalRes) {
                        throw new Error('Something went wrong while approving the token');
                    }
                }
                // generate the contract parameters
                const channelType = config.CHANNEL_TYPE['GENERAL'];
                const identity = '1+' + cid;
                const identityBytes = viem.stringToBytes(identity);
                // call contract
                progressHook === null || progressHook === void 0 ? void 0 : progressHook(progressHook_1.default['PUSH-CREATE-03']);
                const createChannelRes = yield this.createChannel(this.coreContract, channelType, identityBytes, fees);
                progressHook === null || progressHook === void 0 ? void 0 : progressHook(progressHook_1.default['PUSH-CREATE-04']);
                return { transactionHash: createChannelRes };
            }
            catch (error) {
                const errorProgressHook = progressHook_1.default['PUSH-ERROR-02'];
                progressHook === null || progressHook === void 0 ? void 0 : progressHook(errorProgressHook('Create Channel', error));
                throw new Error(`Push SDK Error: Contract : createChannelWithPUSH : ${error}`);
            }
        });
        this.update = (options) => tslib_1.__awaiter(this, void 0, void 0, function* () {
            const { name, description, url, icon, alias = null, progressHook, } = options || {};
            try {
                // create push token instance
                let aliasInfo;
                // validate all the parameters and length
                this.validateChannelParameters(options);
                // check for PUSH balance
                const pushTokenContract = yield this.createContractInstance(config.TOKEN[this.env], config.ABIS.TOKEN, config.TOKEN_VIEM_NETWORK_MAP[this.env]);
                const balance = yield this.fetchBalance(pushTokenContract, this.account);
                // get counter
                const counter = yield this.fetchUpdateCounter(this.coreContract, this.account);
                const fees = viem.parseUnits(config.MIN_TOKEN_BALANCE[this.env].toString(), 18);
                const totalFees = fees * counter;
                if (totalFees > balance) {
                    throw new Error('Insufficient PUSH balance');
                }
                // if alias is passed, check for the caip
                if (alias) {
                    if (!(0, helpers_1.validateCAIP)(alias)) {
                        throw new Error('Invalid alias CAIP');
                    }
                    const aliasDetails = (0, helpers_1.getCAIPDetails)(alias);
                    aliasInfo = {
                        [`${aliasDetails === null || aliasDetails === void 0 ? void 0 : aliasDetails.blockchain}:${aliasDetails === null || aliasDetails === void 0 ? void 0 : aliasDetails.networkId}`]: aliasDetails === null || aliasDetails === void 0 ? void 0 : aliasDetails.address,
                    };
                }
                // construct channel identity
                progressHook === null || progressHook === void 0 ? void 0 : progressHook(progressHook_1.default['PUSH-UPDATE-01']);
                const input = {
                    name: name,
                    info: description,
                    url: url,
                    icon: icon,
                    aliasDetails: aliasInfo !== null && aliasInfo !== void 0 ? aliasInfo : {},
                };
                const cid = yield this.uploadToIPFSViaPushNode(JSON.stringify(input));
                // approve the tokens to core contract
                const allowanceAmount = yield this.fetchAllownace(pushTokenContract, this.account, config.CORE_CONFIG[this.env].EPNS_CORE_CONTRACT);
                // if allowance is not greater than the fees, dont call approval again
                if (!(allowanceAmount >= totalFees)) {
                    progressHook === null || progressHook === void 0 ? void 0 : progressHook(progressHook_1.default['PUSH-UPDATE-02']);
                    const approvalRes = yield this.approveToken(pushTokenContract, config.CORE_CONFIG[this.env].EPNS_CORE_CONTRACT, totalFees);
                    if (!approvalRes) {
                        throw new Error('Something went wrong while approving the token');
                    }
                }
                // generate the contract parameters
                const identity = '1+' + cid;
                const identityBytes = viem.stringToBytes(identity);
                // call contract
                progressHook === null || progressHook === void 0 ? void 0 : progressHook(progressHook_1.default['PUSH-UPDATE-03']);
                const updateChannelRes = yield this.updateChannel(this.coreContract, this.account, identityBytes, totalFees);
                progressHook === null || progressHook === void 0 ? void 0 : progressHook(progressHook_1.default['PUSH-UPDATE-04']);
                return { transactionHash: updateChannelRes };
            }
            catch (error) {
                const errorProgressHook = progressHook_1.default['PUSH-ERROR-02'];
                progressHook === null || progressHook === void 0 ? void 0 : progressHook(errorProgressHook('Update Channel', error));
                throw new Error(`Push SDK Error: Contract channel::update : ${error}`);
            }
        });
        /**
         * @description verifies a channel
         * @param {string} channelToBeVerified - address of the channel to be verified
         * @returns the transaction hash if the transaction is successful
         */
        this.verify = (channelToBeVerified) => tslib_1.__awaiter(this, void 0, void 0, function* () {
            try {
                this.checkSignerObjectExists();
                if ((0, helpers_1.validateCAIP)(channelToBeVerified)) {
                    channelToBeVerified = channelToBeVerified.split(':')[2];
                }
                // checks if it is a valid address
                if (!viem.isAddress(channelToBeVerified)) {
                    throw new Error('Invalid channel address');
                }
                const channelDetails = yield this.info(this.account);
                if ((channelDetails === null || channelDetails === void 0 ? void 0 : channelDetails.verified_status) == 0) {
                    throw new Error('Only verified channel can verify other channel');
                }
                // if valid, continue with it
                const res = yield this.verifyChannel(this.coreContract, channelToBeVerified);
                if (!res) {
                    throw new Error('Something went wrong while verifying the channel');
                }
                return { transactionHash: res };
            }
            catch (error) {
                throw new Error(`Push SDK Error: Contract channel::verify : ${error}`);
            }
        });
        this.setting = (configuration) => tslib_1.__awaiter(this, void 0, void 0, function* () {
            try {
                this.checkSignerObjectExists();
                // check for PUSH balance
                const pushTokenContract = yield this.createContractInstance(config.TOKEN[this.env], config.ABIS.TOKEN, config.TOKEN_VIEM_NETWORK_MAP[this.env]);
                const balance = yield this.fetchBalance(pushTokenContract, this.account);
                const fees = viem.parseUnits(config.MIN_TOKEN_BALANCE[this.env].toString(), 18);
                // get counter
                const counter = yield this.fetchUpdateCounter(this.coreContract, this.account);
                const totalFees = fees * counter;
                if (totalFees > balance) {
                    throw new Error('Insufficient PUSH balance');
                }
                const allowanceAmount = yield this.fetchAllownace(pushTokenContract, this.account, config.CORE_CONFIG[this.env].EPNS_CORE_CONTRACT);
                // if allowance is not greater than the fees, dont call approval again
                if (!(allowanceAmount >= totalFees)) {
                    const approveRes = yield this.approveToken(pushTokenContract, config.CORE_CONFIG[this.env].EPNS_CORE_CONTRACT, totalFees);
                    if (!approveRes) {
                        throw new Error('Something went wrong while approving your token');
                    }
                }
                const { setting, description } = this.getMinimalSetting(configuration);
                const createSettingsRes = yield this.createChanelSettings(this.coreContract, configuration.length, setting, description, fees);
                return { transactionHash: createSettingsRes };
            }
            catch (error) {
                throw new Error(`Push SDK Error: Contract : channel::setting : ${error}`);
            }
        });
        this.notifications = (account, options) => tslib_1.__awaiter(this, void 0, void 0, function* () {
            try {
                const { page, limit, filter = null, raw = true } = options || {};
                return yield PUSH_CHANNEL.getChannelNotifications({
                    channel: account,
                    env: this.env,
                    filter,
                    raw,
                    page,
                    limit,
                });
            }
            catch (error) {
                throw new Error(`Push SDK Error: Contract : channel::notifications : ${error}`);
            }
        });
        this.list = (options) => tslib_1.__awaiter(this, void 0, void 0, function* () {
            try {
                const { page, limit, sort = PushNotificationTypes_1.ChannelListSortType.SUBSCRIBER, order = PushNotificationTypes_1.ChannelListOrderType.DESCENDING, } = options || {};
                return yield PUSH_CHANNEL.getChannels({
                    env: this.env,
                    page,
                    limit,
                    sort,
                    order,
                });
            }
            catch (error) {
                throw new Error(`Push SDK Error: Contract : channel::list : ${error}`);
            }
        });
        this.delegate = new delegate_1.Delegate(signer, env, account);
        this.alias = new alias_1.Alias(env);
    }
}
exports.Channel = Channel;
//# sourceMappingURL=channel.js.map