"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MinimalGraphQLRunner = exports.GraphqlError = exports.GraphQLProviderServiceError = exports.InsufficientScopesError = exports.OutdatedClientVersionError = exports.GraphQLAuthenticationError = exports.BUSINESS_UNITS = exports.NON_PROD_BUSINESS_UNIT = exports.PROD_BUSINESS_UNIT = exports.SERVICE_NAME = void 0;
const graphql_request_1 = require("graphql-request");
const instruction_1 = require("../auth/instruction");
const index_1 = require("../index");
const shared_1 = require("../shared");
const ui_1 = require("../ui");
exports.SERVICE_NAME = 'forge-cli';
exports.PROD_BUSINESS_UNIT = 'Ecosystem - COGS';
exports.NON_PROD_BUSINESS_UNIT = 'Ecosystem Engineering';
exports.BUSINESS_UNITS = {
    DEV: exports.NON_PROD_BUSINESS_UNIT,
    STG: exports.NON_PROD_BUSINESS_UNIT,
    PROD: exports.PROD_BUSINESS_UNIT,
    FEDRAMP_MODERATE_STAGING: exports.NON_PROD_BUSINESS_UNIT,
    FEDRAMP_MODERATE_PROD: exports.PROD_BUSINESS_UNIT
};
class GraphQLAuthenticationError extends shared_1.UserError {
}
exports.GraphQLAuthenticationError = GraphQLAuthenticationError;
const isOutdatedClientVersionError = (error) => error.message?.includes('client version is outdated');
const isInsufficientScopesError = (error) => error.message?.includes('This request does not contain the right authorisation scopes');
class OutdatedClientVersionError extends shared_1.UserError {
    constructor() {
        super(ui_1.Text.graphQL.outdatedClientVersion);
    }
}
exports.OutdatedClientVersionError = OutdatedClientVersionError;
class InsufficientScopesError extends shared_1.UserError {
    constructor() {
        super(ui_1.Text.graphQL.insufficientScopes((0, instruction_1.getInstructionsUrl)()));
    }
}
exports.InsufficientScopesError = InsufficientScopesError;
class GraphQLProviderServiceError extends shared_1.BaseError {
    userError;
    code;
    statusCode;
    requestId;
    constructor(userError, requestId, errors) {
        const { message, code, statusCode } = (0, index_1.getError)(errors);
        super(requestId, `${message} (requestId: ${requestId || 'unknown'})`);
        this.userError = userError;
        this.code = code;
        this.statusCode = statusCode;
        this.requestId = requestId;
    }
    getCode = () => {
        return this.code;
    };
    getStatusCode = () => {
        return this.statusCode;
    };
    getRequestId = () => {
        return this.requestId;
    };
    isUserError() {
        return this.userError;
    }
}
exports.GraphQLProviderServiceError = GraphQLProviderServiceError;
class GraphqlError extends Error {
    constructor(data, requestId) {
        super(`${ui_1.Text.graphQL.error}: ${JSON.stringify(data)}, requestId=${requestId || 'unknown'}`);
    }
}
exports.GraphqlError = GraphqlError;
class MinimalGraphQLRunner {
    authenticator;
    endpoint;
    cliDetails;
    constructor(authenticator, endpoint, cliDetails) {
        this.authenticator = authenticator;
        this.endpoint = endpoint;
        this.cliDetails = cliDetails;
    }
    async run(query, variables) {
        const { data, extensions, headers } = await this.rawRequestWithoutClientError(query, variables);
        const requestId = this.getRequestId(extensions, headers);
        return {
            requestId,
            response: data
        };
    }
    getAuthenticatedClient(endpoint, authorizationHeader) {
        return new graphql_request_1.GraphQLClient(endpoint, {
            headers: this.getHeaders(authorizationHeader)
        });
    }
    getHeaders(authorizationHeader) {
        return {
            ...authorizationHeader,
            ...(this.cliDetails ? { 'user-agent': `${this.getClientName()}/${this.getClientVersion()}` } : {}),
            ...{
                'atl-client-name': `${this.getClientName()}`,
                'atl-client-version': `${this.getClientVersion()}`,
                'atl-attribution': this.getAttribution()
            }
        };
    }
    getAttribution() {
        return JSON.stringify({
            businessUnit: (0, index_1.getEnvironmentConfig)(exports.BUSINESS_UNITS),
            service: exports.SERVICE_NAME
        });
    }
    getClientName() {
        return this.cliDetails?.name || index_1.FORGE_CLI_PACKAGE;
    }
    getClientVersion() {
        return this.cliDetails?.version || 'unknown';
    }
    async rawRequestWithoutClientError(query, variables) {
        const authorizationHeader = await this.authenticator.getAuthorizationHeader();
        const client = this.getAuthenticatedClient(this.endpoint, authorizationHeader);
        try {
            return await client.rawRequest(query, variables);
        }
        catch (error) {
            if (error instanceof graphql_request_1.ClientError) {
                const { data, errors, extensions, headers, status } = error.response;
                if (status === 401) {
                    const errorMessage = this.authenticator.getInstructionsWhenInvalid();
                    throw new GraphQLAuthenticationError(errorMessage);
                }
                const requestId = this.getRequestId(extensions, headers);
                if (errors) {
                    if (errors.find((e) => isOutdatedClientVersionError(e))) {
                        throw new OutdatedClientVersionError();
                    }
                    if (errors.find((e) => isInsufficientScopesError(e))) {
                        throw new InsufficientScopesError();
                    }
                    const { statusCode } = (0, index_1.getError)(errors);
                    const isUserError = statusCode && statusCode >= 400 && statusCode < 500 ? true : false;
                    throw new GraphQLProviderServiceError(isUserError, requestId, errors);
                }
                if (status !== 200) {
                    throw new GraphqlError(data, requestId);
                }
            }
            throw error;
        }
    }
    getRequestId(extensions, headers) {
        return (extensions?.gateway?.request_id ||
            headers?.get('x-request-id') ||
            headers?.get('x-trace-id') ||
            undefined);
    }
}
exports.MinimalGraphQLRunner = MinimalGraphQLRunner;
