import { Gitlab } from "@gitbeaker/node";
import c from "chalk";
import { getCurrentGitBranch, git, uxLog } from "../utils/index.js";
import { GitProviderRoot } from "./gitProviderRoot.js";
import { CONSTANTS } from "../../config/index.js";
export class GitlabProvider extends GitProviderRoot {
    gitlabApi;
    serverUrl;
    token;
    constructor() {
        super();
        // Gitlab URL is always provided by default CI variables
        this.serverUrl = process.env.CI_SERVER_URL || "";
        // It's better to have a project token defined in a CI_SFDX_HARDIS_GITLAB_TOKEN variable, to have the rights to act on Pull Requests
        this.token = process.env.CI_SFDX_HARDIS_GITLAB_TOKEN || process.env.ACCESS_TOKEN || "";
        this.gitlabApi = new Gitlab({
            host: this.serverUrl,
            token: this.token,
            rejectUnauthorized: process?.env?.GITLAB_API_REJECT_UNAUTHORIZED === "false" ? false : true,
        });
    }
    getLabel() {
        return "sfdx-hardis Gitlab connector";
    }
    // Returns current job URL
    async getCurrentJobUrl() {
        if (process.env.PIPELINE_JOB_URL) {
            return process.env.PIPELINE_JOB_URL;
        }
        if (process.env.CI_JOB_URL) {
            return process.env.CI_JOB_URL;
        }
        return null;
    }
    // Returns current job URL
    async getCurrentBranchUrl() {
        if (process.env.CI_PROJECT_URL && process.env.CI_COMMIT_REF_NAME)
            return `${process.env.CI_PROJECT_URL}/-/tree/${process.env.CI_COMMIT_REF_NAME}`;
        return null;
    }
    // Gitlab supports mermaid in PR markdown
    async supportsMermaidInPrMarkdown() {
        return true;
    }
    // Find pull request info
    async getPullRequestInfo() {
        // Case when MR is found in the context
        const projectId = process.env.CI_PROJECT_ID || null;
        const mrNumber = process.env.CI_MERGE_REQUEST_IID || null;
        if (mrNumber !== null) {
            const mergeRequests = await this.gitlabApi.MergeRequests.all({
                projectId: projectId || "",
                iids: [parseInt(mrNumber)],
            });
            if (mergeRequests.length > 0) {
                const mergeRequest = mergeRequests[0];
                return this.completePullRequestInfo(mergeRequest);
            }
        }
        // Case when we find MR from a commit
        const sha = await git().revparse(["HEAD"]);
        const latestMergeRequestsOnBranch = await this.gitlabApi.MergeRequests.all({
            projectId: projectId || "",
            state: "merged",
            sort: "desc",
            sha: sha,
        });
        if (latestMergeRequestsOnBranch.length > 0) {
            const currentGitBranch = await getCurrentGitBranch();
            const candidateMergeRequests = latestMergeRequestsOnBranch.filter((pr) => pr.target_branch === currentGitBranch);
            if (candidateMergeRequests.length > 0) {
                return this.completePullRequestInfo(candidateMergeRequests[0]);
            }
        }
        uxLog("log", this, c.grey(`[Gitlab Integration] Unable to find related Merge Request Info`));
        return null;
    }
    async getBranchDeploymentCheckId(gitBranch) {
        let deploymentCheckId = null;
        const projectId = process.env.CI_PROJECT_ID || null;
        const latestMergeRequestsOnBranch = await this.gitlabApi.MergeRequests.all({
            projectId: projectId || "",
            state: "merged",
            sort: "desc",
            targetBranch: gitBranch,
        });
        if (latestMergeRequestsOnBranch.length > 0) {
            const latestMergeRequest = latestMergeRequestsOnBranch[0];
            const latestMergeRequestId = latestMergeRequest.iid;
            deploymentCheckId = await this.getDeploymentIdFromPullRequest(projectId || "", latestMergeRequestId, deploymentCheckId, this.completePullRequestInfo(latestMergeRequest));
        }
        return deploymentCheckId;
    }
    async getPullRequestDeploymentCheckId() {
        const pullRequestInfo = await this.getPullRequestInfo();
        if (pullRequestInfo) {
            const projectId = process.env.CI_PROJECT_ID || null;
            return await this.getDeploymentIdFromPullRequest(projectId || "", pullRequestInfo.idNumber, null, pullRequestInfo);
        }
        return null;
    }
    async getDeploymentIdFromPullRequest(projectId, latestMergeRequestId, deploymentCheckId, latestMergeRequest) {
        const existingNotes = await this.gitlabApi.MergeRequestNotes.all(projectId, latestMergeRequestId);
        for (const existingNote of existingNotes) {
            if (existingNote.body.includes("<!-- sfdx-hardis deployment-id ")) {
                const matches = /<!-- sfdx-hardis deployment-id (.*) -->/gm.exec(existingNote.body);
                if (matches) {
                    deploymentCheckId = matches[1];
                    uxLog("error", this, c.grey(`Found deployment id ${deploymentCheckId} on MR #${latestMergeRequestId} ${latestMergeRequest.title}`));
                    break;
                }
            }
        }
        return deploymentCheckId;
    }
    // Posts a note on the merge request
    async postPullRequestMessage(prMessage) {
        // Get CI variables
        const projectId = process.env.CI_PROJECT_ID || null;
        const mergeRequestId = process.env.CI_MERGE_REQUEST_IID || process.env.CI_MERGE_REQUEST_ID || null;
        if (projectId == null || mergeRequestId == null) {
            uxLog("log", this, c.grey("[Gitlab integration] No project and merge request, so no note posted..."));
            return { posted: false, providerResult: { info: "No related merge request" } };
        }
        const gitlabCiJobName = process.env.CI_JOB_NAME;
        const gitlabCIJobUrl = process.env.CI_JOB_URL;
        // Build note message
        const messageKey = prMessage.messageKey + "-" + gitlabCiJobName + "-" + mergeRequestId;
        let messageBody = `**${prMessage.title || ""}**

${prMessage.message}

_Powered by [sfdx-hardis](${CONSTANTS.DOC_URL_ROOT}) from job [${gitlabCiJobName}](${gitlabCIJobUrl})_
<!-- sfdx-hardis message-key ${messageKey} -->
`;
        // Add deployment id if present
        if (globalThis.pullRequestDeploymentId) {
            messageBody += `\n<!-- sfdx-hardis deployment-id ${globalThis.pullRequestDeploymentId} -->`;
        }
        // Check for existing note from a previous run
        uxLog("log", this, c.grey("[Gitlab integration] Listing Notes of Merge Request..."));
        const existingNotes = await this.gitlabApi.MergeRequestNotes.all(projectId, mergeRequestId);
        let existingNoteId = null;
        for (const existingNote of existingNotes) {
            if (existingNote.body.includes(`<!-- sfdx-hardis message-key ${messageKey} -->`)) {
                existingNoteId = existingNote.id;
            }
        }
        // Create or update MR note
        if (existingNoteId) {
            // Update existing note
            uxLog("log", this, c.grey("[Gitlab integration] Updating Merge Request Note on Gitlab..."));
            const gitlabEditNoteResult = await this.gitlabApi.MergeRequestNotes.edit(projectId, mergeRequestId, existingNoteId, messageBody);
            const prResult = {
                posted: gitlabEditNoteResult.id > 0,
                providerResult: gitlabEditNoteResult,
            };
            return prResult;
        }
        else {
            // Create new note if no existing not was found
            uxLog("log", this, c.grey("[Gitlab integration] Adding Merge Request Note on Gitlab..."));
            const gitlabPostNoteResult = await this.gitlabApi.MergeRequestNotes.create(projectId, mergeRequestId, messageBody);
            const prResult = {
                posted: gitlabPostNoteResult.id > 0,
                providerResult: gitlabPostNoteResult,
            };
            return prResult;
        }
    }
    completePullRequestInfo(prData) {
        const prInfo = {
            idNumber: prData?.iid || prData?.id || 0,
            idStr: String(prData?.iid || prData?.id || ""),
            sourceBranch: (prData?.source_branch || "").replace("refs/heads/", ""),
            targetBranch: (prData?.target_branch || "").replace("refs/heads/", ""),
            title: prData?.title || "",
            description: prData?.description || "",
            authorName: prData?.author?.name || "",
            webUrl: prData?.web_url || "",
            providerInfo: prData,
            customBehaviors: {}
        };
        return this.completeWithCustomBehaviors(prInfo);
    }
}
//# sourceMappingURL=gitlab.js.map