"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateCodeReportForCommit = generateCodeReportForCommit;
exports.generateCodeAnnotationsForReport = generateCodeAnnotationsForReport;
exports.putCodeReportAndAnnotations = putCodeReportAndAnnotations;
exports.maybeOutputToBitbucket = maybeOutputToBitbucket;
const CodeReport_1 = require("@mablhq-internal/runtime/api/atlassian/entities/CodeReport");
const moment = require("moment");
const bitBucketApiClient_1 = require("@mablhq-internal/runtime/api/atlassian/bitBucketApiClient");
const CodeAnnotation_1 = require("@mablhq-internal/runtime/api/atlassian/entities/CodeAnnotation");
const loggingProvider_1 = require("@mablhq-internal/runtime/providers/logging/loggingProvider");
const logUtils_1 = require("@mablhq-internal/runtime/util/logUtils");
const pureUtil_1 = require("@mablhq-internal/runtime/util/pureUtil");
const chalk = require('chalk');
const bitbucketUserKey = 'MABL_BITBUCKET_USER';
const bitbucketAppToken = 'MABL_BITBUCKET_APP_TOKEN';
function generateCodeReportForCommit(executionEventId, outputLink, executionResult) {
    const codeReport = {
        report_type: CodeReport_1.CodeReportType.TEST,
        external_id: `${executionEventId}-cr`,
        title: `mabl tests`,
        details: `mabl tests for mabl deployment ${executionEventId}`,
        result: executionResult.event_status?.succeeded
            ? CodeReport_1.CodeInsightsResult.PASSED
            : CodeReport_1.CodeInsightsResult.FAILED,
        reporter: `mabl`,
        link: outputLink,
        logo_url: 'https://storage.cloud.google.com/mabl-email-static-assets/mabl_logo.png',
        created_on: moment().toISOString(),
    };
    codeReport.data = [
        {
            title: 'mabl App',
            type: 'LINK',
            value: {
                text: 'View results',
                href: outputLink,
            },
        },
        {
            title: 'Plans run',
            type: 'NUMBER',
            value: executionResult.plan_execution_metrics?.total,
        },
        {
            title: 'Plans failed',
            type: 'NUMBER',
            value: executionResult.plan_execution_metrics?.failed,
        },
        {
            title: 'Tests run',
            type: 'NUMBER',
            value: executionResult.journey_execution_metrics?.total,
        },
        {
            title: 'Tests failed',
            type: 'NUMBER',
            value: executionResult.journey_execution_metrics?.failed,
        },
    ];
    if (executionResult.journey_execution_metrics?.total ?? 0 > 0) {
        const percentPassing = parseFloat((((executionResult.journey_execution_metrics?.passed ?? 0) /
            (executionResult.journey_execution_metrics?.total ?? 1)) *
            100).toFixed(2));
        codeReport.data.push({
            title: 'Tests passing percent',
            type: 'PERCENTAGE',
            value: percentPassing,
        });
    }
    if (executionResult.executions) {
        const minStartTimes = [];
        executionResult.executions.forEach((execution) => {
            if (execution.start_time) {
                minStartTimes.push(execution.start_time);
            }
        });
        const maxStartTimes = [];
        executionResult.executions.forEach((execution) => {
            if (execution.stop_time) {
                maxStartTimes.push(execution.stop_time);
            }
        });
        if (maxStartTimes && minStartTimes) {
            const duration = Math.max(...maxStartTimes) - Math.min(...minStartTimes);
            codeReport.data.push({
                title: 'Total duration',
                type: 'DURATION',
                value: duration,
            });
        }
    }
    return codeReport;
}
function generateCodeAnnotationsForReport(executionResult) {
    const codeAnnotations = [];
    if (executionResult.executions) {
        executionResult.executions.forEach((execution) => {
            if (execution.journey_executions) {
                execution.journey_executions.forEach((testExecution) => {
                    const codeAnnotation = {
                        external_id: `${testExecution.journey_execution_id}-ca`,
                        annotation_type: CodeAnnotation_1.CodeInsightsAnnotationType.BUG,
                        summary: generateAnnotationSummary(testExecution, execution.journeys),
                        result: testExecution.success
                            ? CodeReport_1.CodeInsightsResult.PASSED
                            : CodeReport_1.CodeInsightsResult.FAILED,
                        details: generateAnnotationDetails(testExecution),
                        link: testExecution.app_href,
                        created_on: moment(testExecution.stop_time).toISOString(),
                    };
                    codeAnnotations.push(codeAnnotation);
                });
            }
        });
    }
    return codeAnnotations;
}
function generateAnnotationDetails(testExecution) {
    if (testExecution.success) {
        return `Test was successful - Browser: "${testExecution.browser_type}"`;
    }
    return `Failure Error: "${testExecution.failure_summary?.error}" - Browser: "${testExecution.browser_type}"`;
}
function generateAnnotationSummary(testExecution, journeySummaries) {
    let testForAnnotation;
    if (journeySummaries) {
        testForAnnotation = journeySummaries.find((test) => test.id === testExecution.journey_id);
    }
    if (testForAnnotation) {
        return `${testForAnnotation.name}`;
    }
    return `"${testExecution.journey_id}" test finished with status ${testExecution.status}`;
}
async function putCodeReportAndAnnotations(executionResult, executionEventId, outputLink, workspace, repoSlug, node, isCustomBitBucketPipe, noProxy) {
    const codeReport = generateCodeReportForCommit(executionEventId, outputLink, executionResult);
    const bitBucketApiClient = getBitBucketApiClient(isCustomBitBucketPipe, noProxy);
    const codeReportResponse = await bitBucketApiClient.putCodeReport(codeReport, workspace, repoSlug, node);
    const codeAnnotations = generateCodeAnnotationsForReport(executionResult);
    const requests = codeAnnotations.map((annotation) => bitBucketApiClient.putCodeAnnotation(annotation, workspace, repoSlug, node, codeReportResponse.external_id));
    const results = await Promise.allSettled(requests);
    (0, logUtils_1.logPromiseSettledRejections)(results);
    if (results.some(pureUtil_1.isRejectedPromise)) {
        throw new Error('Error writing Code Annotations to Bitbucket');
    }
    return codeReportResponse;
}
async function maybeOutputToBitbucket(executionResult, deploymentId, outputLink) {
    const repoSlug = process.env.BITBUCKET_REPO_SLUG ?? '';
    const workspace = process.env.BITBUCKET_REPO_OWNER ?? '';
    const node = process.env.BITBUCKET_COMMIT ?? '';
    const isCustomBitBucketPipe = process.env.IS_CUSTOM_BITBUCKET_PIPE === 'true';
    const noProxy = process.env.CODE_INSIGHTS_PROXY_OFF === 'true';
    if (repoSlug &&
        workspace &&
        node &&
        executionResult?.executions?.length &&
        executionResult.executions.length > 0) {
        const codeReport = await putCodeReportAndAnnotations(executionResult, deploymentId, outputLink, workspace, repoSlug, node, isCustomBitBucketPipe, noProxy);
        loggingProvider_1.logger.info(chalk.cyan(`Bitbucket Code Insights Report generated ${codeReport.uuid}`));
    }
    return;
}
function getBitBucketApiClient(isCustomPipe, noProxy) {
    if (noProxy) {
        const username = process.env[bitbucketUserKey];
        const token = process.env[bitbucketAppToken];
        if (!username || !token) {
            throw new Error(`Auth config not supplied for Bitbucket output. Please define ${bitbucketUserKey} and ${bitbucketAppToken} environment variables`);
        }
        return new bitBucketApiClient_1.BitBucketApiClient(username, token, isCustomPipe, noProxy);
    }
    if (isCustomPipe) {
        return new bitBucketApiClient_1.BitBucketApiClient('', '', isCustomPipe, noProxy);
    }
    return new bitBucketApiClient_1.BitBucketApiClient('', '', isCustomPipe, noProxy);
}
