"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());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.deleteIndexingRules = exports.setIndexingRule = exports.indexingRule = exports.indexingRules = exports.printIndexingRules = exports.displayIndexingRule = exports.displayIndexingRules = exports.indexingRuleToGraphQL = exports.indexingRuleFromGraphQL = exports.formatIndexingRule = exports.parseIndexingRule = exports.parseDecisionBasis = exports.parseDeploymentID = void 0;
const common_ts_1 = require("@graphprotocol/common-ts");
const graphql_tag_1 = __importDefault(require("graphql-tag"));
const yaml_1 = __importDefault(require("yaml"));
const table_1 = require("table");
const ethers_1 = require("ethers");
const command_helpers_1 = require("./command-helpers");
exports.parseDeploymentID = (s) => {
    if (s === 'all' || s === 'global') {
        return s;
    }
    else {
        return new common_ts_1.SubgraphDeploymentID(s);
    }
};
exports.parseDecisionBasis = (s) => {
    if (!['always', 'never', 'rules'].includes(s)) {
        throw new Error(`Unknown decision basis "${s}". Supported: always, never, rules`);
    }
    else {
        return s;
    }
};
function nullPassThrough(fn) {
    return (x) => (x === null ? null : fn(x));
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const INDEXING_RULE_PARSERS = {
    id: x => x,
    deployment: exports.parseDeploymentID,
    allocationAmount: nullPassThrough(common_ts_1.parseGRT),
    parallelAllocations: nullPassThrough(parseInt),
    minSignal: nullPassThrough(common_ts_1.parseGRT),
    maxSignal: nullPassThrough(common_ts_1.parseGRT),
    minStake: nullPassThrough(common_ts_1.parseGRT),
    maxAllocationPercentage: nullPassThrough(parseFloat),
    minAverageQueryFees: nullPassThrough(common_ts_1.parseGRT),
    decisionBasis: nullPassThrough(exports.parseDecisionBasis),
    custom: nullPassThrough(JSON.parse),
};
const INDEXING_RULE_FORMATTERS = {
    id: nullPassThrough(x => x),
    deployment: (d) => (typeof d === 'string' ? d : d.ipfsHash),
    allocationAmount: nullPassThrough(x => ethers_1.utils.commify(common_ts_1.formatGRT(x))),
    parallelAllocations: nullPassThrough((x) => x.toString()),
    minSignal: nullPassThrough(x => ethers_1.utils.commify(common_ts_1.formatGRT(x))),
    maxSignal: nullPassThrough(x => ethers_1.utils.commify(common_ts_1.formatGRT(x))),
    minStake: nullPassThrough(x => ethers_1.utils.commify(common_ts_1.formatGRT(x))),
    maxAllocationPercentage: nullPassThrough((x) => x.toPrecision(2)),
    minAverageQueryFees: nullPassThrough(x => ethers_1.utils.commify(common_ts_1.formatGRT(x))),
    decisionBasis: x => x,
    custom: nullPassThrough(JSON.stringify),
};
const INDEXING_RULE_CONVERTERS_FROM_GRAPHQL = {
    id: x => x,
    deployment: exports.parseDeploymentID,
    allocationAmount: nullPassThrough((x) => ethers_1.BigNumber.from(x)),
    parallelAllocations: nullPassThrough((x) => parseInt(x)),
    minSignal: nullPassThrough((x) => ethers_1.BigNumber.from(x)),
    maxSignal: nullPassThrough((x) => ethers_1.BigNumber.from(x)),
    minStake: nullPassThrough((x) => ethers_1.BigNumber.from(x)),
    maxAllocationPercentage: nullPassThrough((x) => parseFloat(x)),
    minAverageQueryFees: nullPassThrough((x) => ethers_1.BigNumber.from(x)),
    decisionBasis: x => x,
    custom: nullPassThrough(JSON.stringify),
};
const INDEXING_RULE_CONVERTERS_TO_GRAPHQL = {
    id: x => x,
    deployment: (x) => x.toString(),
    allocationAmount: nullPassThrough((x) => x.toString()),
    parallelAllocations: nullPassThrough((x) => x),
    minSignal: nullPassThrough((x) => x.toString()),
    maxSignal: nullPassThrough((x) => x.toString()),
    minStake: nullPassThrough((x) => x.toString()),
    maxAllocationPercentage: nullPassThrough((x) => x),
    minAverageQueryFees: nullPassThrough((x) => x.toString()),
    decisionBasis: x => x,
    custom: nullPassThrough(JSON.stringify),
};
/**
 * Parses a user-provided indexing rule into a normalized form.
 */
exports.parseIndexingRule = (rule) => {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const obj = {};
    for (const [key, value] of Object.entries(rule)) {
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        obj[key] = INDEXING_RULE_PARSERS[key](value);
    }
    return obj;
};
/**
 * Formats an indexing rule for display in the console.
 */
exports.formatIndexingRule = (rule) => {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const obj = {};
    for (const [key, value] of Object.entries(rule)) {
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        obj[key] = INDEXING_RULE_FORMATTERS[key](value);
    }
    return obj;
};
/**
 * Parses an indexing rule returned from the indexer management GraphQL
 * API into normalized form.
 */
exports.indexingRuleFromGraphQL = (rule) => {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const obj = {};
    for (const [key, value] of Object.entries(command_helpers_1.pickFields(rule, []))) {
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        obj[key] = INDEXING_RULE_CONVERTERS_FROM_GRAPHQL[key](value);
    }
    return obj;
};
/**
 * Converts a normalized indexing rule to a representation
 * compatible with the indexer management GraphQL API.
 */
exports.indexingRuleToGraphQL = (rule) => {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const obj = {};
    for (const [key, value] of Object.entries(rule)) {
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        obj[key] = INDEXING_RULE_CONVERTERS_TO_GRAPHQL[key](value);
    }
    return obj;
};
exports.displayIndexingRules = (outputFormat, rules) => outputFormat === 'json'
    ? JSON.stringify(rules, null, 2)
    : outputFormat === 'yaml'
        ? yaml_1.default.stringify(rules).trim()
        : rules.length === 0
            ? 'No data'
            : table_1.table([Object.keys(rules[0]), ...rules.map(rule => Object.values(rule))], {
                border: table_1.getBorderCharacters('norc'),
            }).trim();
exports.displayIndexingRule = (outputFormat, rule) => outputFormat === 'json'
    ? JSON.stringify(rule, null, 2)
    : outputFormat === 'yaml'
        ? yaml_1.default.stringify(rule).trim()
        : table_1.table([Object.keys(rule), Object.values(rule)], {
            border: table_1.getBorderCharacters('norc'),
        }).trim();
exports.printIndexingRules = (print, outputFormat, deployment, ruleOrRules, keys) => {
    if (Array.isArray(ruleOrRules)) {
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        const rules = ruleOrRules.map(rule => exports.formatIndexingRule(command_helpers_1.pickFields(rule, keys)));
        print.info(exports.displayIndexingRules(outputFormat, rules));
    }
    else if (ruleOrRules) {
        const rule = exports.formatIndexingRule(command_helpers_1.pickFields(ruleOrRules, keys));
        print.info(exports.displayIndexingRule(outputFormat, rule));
    }
    else if (deployment) {
        print.error(`No rule found for "${deployment}"`);
    }
    else {
        print.error(`No indexing rules found`);
    }
};
exports.indexingRules = (client, merged) => __awaiter(void 0, void 0, void 0, function* () {
    const result = yield client
        .query(graphql_tag_1.default `
        query indexingRules($merged: Boolean!) {
          indexingRules(merged: $merged) {
            deployment
            allocationAmount
            parallelAllocations
            maxAllocationPercentage
            minSignal
            maxSignal
            minStake
            minAverageQueryFees
            custom
            decisionBasis
          }
        }
      `, { merged: !!merged })
        .toPromise();
    if (result.error) {
        throw result.error;
    }
    return result.data.indexingRules.map(exports.indexingRuleFromGraphQL);
});
exports.indexingRule = (client, deployment, merged) => __awaiter(void 0, void 0, void 0, function* () {
    const result = yield client
        .query(graphql_tag_1.default `
        query indexingRule($deployment: String!, $merged: Boolean!) {
          indexingRule(deployment: $deployment, merged: $merged) {
            deployment
            allocationAmount
            parallelAllocations
            maxAllocationPercentage
            minSignal
            maxSignal
            minStake
            minAverageQueryFees
            custom
            decisionBasis
          }
        }
      `, { deployment: deployment.toString(), merged })
        .toPromise();
    if (result.error) {
        throw result.error;
    }
    if (result.data.indexingRule) {
        return exports.indexingRuleFromGraphQL(result.data.indexingRule);
    }
    else {
        return null;
    }
});
exports.setIndexingRule = (client, rule) => __awaiter(void 0, void 0, void 0, function* () {
    const result = yield client
        .mutation(graphql_tag_1.default `
        mutation setIndexingRule($rule: IndexingRuleInput!) {
          setIndexingRule(rule: $rule) {
            deployment
            allocationAmount
            parallelAllocations
            maxAllocationPercentage
            minSignal
            maxSignal
            minStake
            minAverageQueryFees
            custom
            decisionBasis
          }
        }
      `, { rule: exports.indexingRuleToGraphQL(rule) })
        .toPromise();
    if (result.error) {
        throw result.error;
    }
    return exports.indexingRuleFromGraphQL(result.data.setIndexingRule);
});
exports.deleteIndexingRules = (client, deployments) => __awaiter(void 0, void 0, void 0, function* () {
    const result = yield client
        .mutation(graphql_tag_1.default `
        mutation deleteIndexingRules($deployments: [String!]!) {
          deleteIndexingRules(deployments: $deployments)
        }
      `, { deployments: deployments.map(deployment => deployment.toString()) })
        .toPromise();
    if (result.error) {
        throw result.error;
    }
});
