"use strict";
/* eslint-disable @typescript-eslint/ban-types */
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 ngeohash_1 = __importDefault(require("ngeohash"));
const graphql_tag_1 = __importDefault(require("graphql-tag"));
const common_ts_1 = require("@graphprotocol/common-ts");
const indexer_common_1 = require("@graphprotocol/indexer-common");
const testURL = (url, tests) => __awaiter(void 0, void 0, void 0, function* () {
    const results = [];
    for (const test of tests) {
        const cmd = test.test(url);
        try {
            yield test.run(url);
            results.push({
                test: cmd,
                error: null,
                possibleActions: [],
            });
        }
        catch (e) {
            results.push({
                test: cmd,
                error: e.message,
                possibleActions: test.possibleActions(url),
            });
        }
    }
    return { url, tests: results, ok: !results.find((result) => result.error !== null) };
});
const URL_VALIDATION_TEST = {
    test: () => `URL validation`,
    run: (url) => __awaiter(void 0, void 0, void 0, function* () {
        new URL(url);
    }),
    possibleActions: (url) => [`Make sure ${url} is a valid URL`],
};
exports.default = {
    indexerRegistration: (_, { address, contracts }) => __awaiter(void 0, void 0, void 0, function* () {
        const registered = yield contracts.serviceRegistry.isRegistered(address);
        if (registered) {
            const service = yield contracts.serviceRegistry.services(address);
            return {
                address,
                url: service.url,
                location: ngeohash_1.default.decode(service.geohash),
                registered,
                __typename: 'IndexerRegistration',
            };
        }
        else {
            return {
                address,
                url: null,
                registered,
                location: null,
                __typename: 'IndexerRegistration',
            };
        }
    }),
    indexerDeployments: (_, { indexingStatusResolver }) => __awaiter(void 0, void 0, void 0, function* () {
        const result = yield indexingStatusResolver.indexingStatus([]);
        return result.map((status) => (Object.assign(Object.assign({}, status), { subgraphDeployment: status.subgraphDeployment.ipfsHash })));
    }),
    indexerAllocations: (_, { address, networkSubgraph, logger }) => __awaiter(void 0, void 0, void 0, function* () {
        try {
            const result = yield networkSubgraph.query(graphql_tag_1.default `
          query allocations($indexer: String!) {
            allocations(
              where: { indexer: $indexer, status: Active }
              first: 1000
              orderDirection: desc
            ) {
              id
              allocatedTokens
              createdAtEpoch
              closedAtEpoch
              subgraphDeployment {
                id
                stakedTokens
                signalAmount
              }
            }
          }
        `, { indexer: address.toLocaleLowerCase() });
            if (result.error) {
                throw result.error;
            }
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
            return result.data.allocations.map((allocation) => (Object.assign(Object.assign({}, allocation), { subgraphDeployment: new common_ts_1.SubgraphDeploymentID(allocation.subgraphDeployment.id)
                    .ipfsHash, signalAmount: allocation.subgraphDeployment.signalAmount, stakedTokens: allocation.subgraphDeployment.stakedTokens })));
        }
        catch (error) {
            const err = indexer_common_1.indexerError(indexer_common_1.IndexerErrorCode.IE010, error);
            logger === null || logger === void 0 ? void 0 : logger.error(`Failed to query indexer allocations`, {
                err,
            });
            throw err;
        }
    }),
    indexerEndpoints: (_, { address, contracts, logger }) => __awaiter(void 0, void 0, void 0, function* () {
        const endpoints = {
            service: {
                url: null,
                healthy: false,
                tests: [],
            },
            status: {
                url: null,
                healthy: false,
                tests: [],
            },
        };
        try {
            const service = yield contracts.serviceRegistry.services(address);
            if (service) {
                {
                    const { url, tests, ok } = yield testURL(service.url, [
                        URL_VALIDATION_TEST,
                        {
                            test: (url) => `http get ${url}`,
                            run: (url) => __awaiter(void 0, void 0, void 0, function* () {
                                const response = yield fetch(url);
                                if (!response.ok) {
                                    throw new Error(`Returned status ${response.status}: ${response.body ? response.body.toString() : 'No data returned'}`);
                                }
                            }),
                            possibleActions: (url) => [
                                `Make sure ${url} can be resolved and reached from this machine`,
                                `Make sure the port of ${url} is set up correctly`,
                                `Make sure the test command returns an HTTP status code < 400`,
                            ],
                        },
                    ]);
                    endpoints.service.url = url;
                    endpoints.service.healthy = ok;
                    endpoints.service.tests = tests;
                }
                {
                    const statusURL = endpoints.service.url.endsWith('/')
                        ? endpoints.service.url.substring(0, endpoints.service.url.length - 1) +
                            '/status'
                        : endpoints.service.url + '/status';
                    const { url, tests, ok } = yield testURL(statusURL, [
                        URL_VALIDATION_TEST,
                        {
                            test: (url) => `http post ${url} query="{ indexingStatuses { subgraph } }"`,
                            run: (url) => __awaiter(void 0, void 0, void 0, function* () {
                                const response = yield fetch(url, {
                                    method: 'POST',
                                    headers: { 'content-type': 'application/json' },
                                    body: JSON.stringify({ query: '{ indexingStatuses { subgraph } }' }),
                                });
                                if (!response.ok) {
                                    throw new Error(`Returned status ${response.status}: ${response.body ? response.body.toString() : 'No data returned'}`);
                                }
                            }),
                            possibleActions: (url) => [
                                `Make sure ${url} can be reached from this machine`,
                                `Make sure the port of ${url} is set up correctly`,
                                `Make sure ${url} is the /status endpoint of indexer-service`,
                                `Make sure the test command returns an HTTP status code < 400`,
                                `Make sure the test command returns a valid GraphQL response`,
                            ],
                        },
                    ]);
                    endpoints.status.url = url;
                    endpoints.status.healthy = ok;
                    endpoints.status.tests = tests;
                }
            }
        }
        catch (err) {
            // Return empty endpoints
            logger === null || logger === void 0 ? void 0 : logger.warn(`Failed to detect service endpoints`, { err });
        }
        return endpoints;
    }),
};
//# sourceMappingURL=indexer-status.js.map