"use strict";
/* eslint-disable @typescript-eslint/no-explicit-any */
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 });
const chalk_1 = __importDefault(require("chalk"));
const config_1 = require("../../config");
const client_1 = require("../../client");
const graphql_tag_1 = __importDefault(require("graphql-tag"));
const rules_1 = require("../../rules");
const allocations_1 = require("../../allocations");
const command_helpers_1 = require("../../command-helpers");
const HELP = `
${chalk_1.default.bold('graph indexer status')}

${chalk_1.default.dim('Options:')}

  -h, --help                    Show usage information
`;
module.exports = {
    name: 'status',
    alias: [],
    description: 'Check the status of an indexer',
    run: (toolbox) => __awaiter(void 0, void 0, void 0, function* () {
        const { print } = toolbox;
        const { h, help, o, output } = toolbox.parameters.options;
        const outputFormat = o || output || 'table';
        if (help || h) {
            print.info(HELP);
            return;
        }
        if (!['json', 'yaml', 'table'].includes(outputFormat)) {
            print.error(`Invalid output format "${outputFormat}"`);
            process.exitCode = 1;
            return;
        }
        const config = config_1.loadValidatedConfig();
        // Create indexer API client
        const client = yield client_1.createIndexerManagementClient({ url: config.api });
        // Query status information
        let result;
        try {
            result = yield client
                .query(graphql_tag_1.default `
            query {
              indexerRegistration {
                url
                address
                registered
                location {
                  latitude
                  longitude
                }
              }

              indexerDeployments {
                subgraphDeployment
                synced
                health
                fatalError {
                  handler
                  message
                }
                node
                chains {
                  network
                  latestBlock {
                    number
                  }
                  chainHeadBlock {
                    number
                  }
                  earliestBlock {
                    number
                  }
                }
              }

              indexerAllocations {
                id
                allocatedTokens
                createdAtEpoch
                closedAtEpoch
                subgraphDeployment
                signalAmount
                stakedTokens
              }

              indexerEndpoints {
                service {
                  url
                  healthy
                  tests {
                    test
                    error
                    possibleActions
                  }
                }
                status {
                  url
                  healthy
                  tests {
                    test
                    error
                    possibleActions
                  }
                }
              }

              indexingRules(merged: true) {
                deployment
                allocationAmount
                parallelAllocations
                maxAllocationPercentage
                minSignal
                maxSignal
                minStake
                minAverageQueryFees
                custom
                decisionBasis
              }
            }
          `, {})
                .toPromise();
        }
        catch (error) {
            print.error(`Failed to fetch status information: ${error}`);
            process.exit(1);
        }
        if (result.error) {
            print.error(`Error fetching status information: ${result.error}`);
            process.exit(1);
        }
        const data = {
            registration: null,
            endpoints: null,
            indexerDeployments: null,
            indexerAllocations: null,
            indexingRules: null,
        };
        if (result.data.indexerRegistration) {
            data.registration = command_helpers_1.pickFields(result.data.indexerRegistration, []);
            data.registration.location = `${data.registration.location.latitude},${data.registration.location.longitude}`;
        }
        else {
            data.registration = {
                error: 'Not registered yet. Make sure to run `indexer-agent` and register on chain',
            };
        }
        if (result.data.indexerEndpoints) {
            const keys = Object.keys(command_helpers_1.pickFields(result.data.indexerEndpoints, []));
            keys.sort();
            const statusUp = outputFormat == 'table' ? chalk_1.default.green('up') : 'up';
            const statusDown = outputFormat == 'table' ? chalk_1.default.red('down') : 'down';
            data.endpoints = keys.reduce((out, key) => [
                ...out,
                {
                    name: key,
                    url: result.data.indexerEndpoints[key].url,
                    status: result.data.indexerEndpoints[key].healthy ? statusUp : statusDown,
                    tests: result.data.indexerEndpoints[key].tests,
                },
            ], []);
        }
        else {
            data.endpoints = {
                error: 'Indexer endpoints unknown. Make sure to run `indexer-agent` and register on chain',
            };
        }
        if (result.data.indexerDeployments) {
            data.indexerDeployments = result.data.indexerDeployments;
        }
        if (result.data.indexerAllocations) {
            data.indexerAllocations = result.data.indexerAllocations.map(allocations_1.indexerAllocationFromGraphQL);
        }
        if (result.data.indexingRules) {
            if (result.data.indexingRules.length === 0) {
                data.indexingRules = [
                    {
                        error: 'No indexing rules defined, make sure `indexer-agent` is starting without issues',
                    },
                ];
            }
            else {
                result.data.indexingRules.sort((a, b) => a.deployment.localeCompare(b.deployment));
                data.indexingRules = result.data.indexingRules.map(rules_1.indexingRuleFromGraphQL);
            }
        }
        if (outputFormat === 'table') {
            print.info('Registration');
            print.info(command_helpers_1.formatData(data.registration, outputFormat));
            print.info('');
            print.info('Endpoints');
            if (data.endpoints.error) {
                print.info(command_helpers_1.formatData([data.endpoints], outputFormat));
            }
            else {
                print.info(command_helpers_1.formatData(data.endpoints.map((endpoint) => command_helpers_1.pickFields(endpoint, ['name', 'url', 'status'])), outputFormat));
                if (data.endpoints.find((endpoint) => endpoint.tests.find((test) => test.error !== null))) {
                    print.error('The following endpoint tests failed:\n');
                    for (const endpoint of data.endpoints) {
                        const failingTests = endpoint.tests.filter((test) => test.error !== null);
                        if (failingTests.length > 0) {
                            print.error(endpoint.url);
                            for (const test of failingTests) {
                                print.error(`  Test: ${test.test}`);
                                print.error(`  Error: ${test.error}`);
                                print.error(`  Possible actions:`);
                                for (const action of test.possibleActions) {
                                    print.error(`    - ${action}`);
                                }
                            }
                        }
                    }
                }
            }
            print.info('');
            print.info('Indexer Deployments');
            if (data.indexerDeployments) {
                print.info(command_helpers_1.formatData(data.indexerDeployments.flatMap((deployment) => deployment.chains.map((chain) => ({
                    deployment: deployment.subgraphDeployment,
                    synced: deployment.synced,
                    health: deployment.health,
                    fatalError: deployment.fatalError
                        ? JSON.stringify(deployment.fatalError.message)
                        : '-',
                    node: deployment.node,
                    network: chain.network,
                    latestBlockNumber: chain.latestBlock.number,
                    chainHeadBlockNumber: chain.chainHeadBlock.number,
                    earliestBlockNumber: chain.earliestBlock.number,
                }))), outputFormat));
            }
            print.info('');
            print.info('Indexer Allocations');
            if (data.indexerAllocations) {
                allocations_1.printIndexerAllocations(print, outputFormat, data.indexerAllocations, [
                    'id',
                    'subgraphDeployment',
                    'allocatedTokens',
                    'createdAtEpoch',
                    'signalAmount',
                    'stakedTokens',
                ]);
            }
            print.info('');
            print.info('Indexing Rules');
            if (data.indexingRules.length === 1 && data.indexingRules[0].error) {
                print.info(command_helpers_1.formatData(data.indexingRules[0], outputFormat));
            }
            else {
                rules_1.printIndexingRules(print, outputFormat, null, data.indexingRules, []);
            }
        }
        else {
            print.info(command_helpers_1.formatData(data, outputFormat));
        }
    }),
};
