import * as github from "@actions/github";
import c from "chalk";
import { GitProviderRoot } from "./gitProviderRoot.js";
import { getCurrentGitBranch, git, uxLog } from "../utils/index.js";
import { CONSTANTS } from "../../config/index.js";
export class GithubProvider extends GitProviderRoot {
    octokit;
    repoOwner;
    repoName;
    serverUrl;
    workflow;
    branch;
    prNumber;
    runId;
    constructor() {
        super();
        const tokenName = process.env.CI_SFDX_HARDIS_GITHUB_TOKEN ? "CI_SFDX_HARDIS_GITHUB_TOKEN" : process.env.PAT ? "PAT" : "GITHUB_TOKEN";
        const token = process.env[tokenName];
        this.octokit = github.getOctokit(token || "");
        this.repoOwner = github?.context?.repo?.owner || process.env.GITHUB_REPOSITORY_OWNER || null;
        this.repoName = github?.context?.repo?.repo || process.env?.GITHUB_REPOSITORY?.split("/")[1] || null;
        this.serverUrl = github?.context?.serverUrl || process.env.GITHUB_SERVER_URL || null;
        this.workflow = github?.context?.workflow || process.env.GITHUB_WORKFLOW || null;
        this.branch = github?.context?.ref || process.env.GITHUB_REF || null;
        this.prNumber = github?.context?.payload?.pull_request?.number || (process.env.GITHUB_REF_NAME ? parseInt(process.env.GITHUB_REF_NAME.split("/")?.[0] || "0") : null);
        this.runId = github?.context?.runId || process.env.GITHUB_RUN_ID || null;
    }
    getLabel() {
        return "sfdx-hardis GitHub connector";
    }
    async getBranchDeploymentCheckId(gitBranch) {
        let deploymentCheckId = null;
        uxLog("log", this, c.grey("[GitHub Integration] Listing previously closed Pull Requests"));
        const latestPullRequestsOnBranch = await this.octokit.rest.pulls.list({
            owner: this.repoOwner || "",
            repo: this.repoName || "",
            state: "closed",
            direction: "desc",
            per_page: 10,
            base: gitBranch,
        });
        if (latestPullRequestsOnBranch.data.length > 0) {
            const latestPullRequest = latestPullRequestsOnBranch.data[0];
            const latestPullRequestId = latestPullRequest.number;
            deploymentCheckId = await this.getDeploymentIdFromPullRequest(latestPullRequestId, this.repoOwner || "", this.repoName || "", deploymentCheckId, latestPullRequest);
        }
        return deploymentCheckId;
    }
    async getPullRequestDeploymentCheckId() {
        const pullRequestInfo = await this.getPullRequestInfo();
        if (pullRequestInfo) {
            return await this.getDeploymentIdFromPullRequest(pullRequestInfo.idNumber, this.repoOwner || "", this.repoName || "", null, pullRequestInfo);
        }
        return null;
    }
    async getDeploymentIdFromPullRequest(latestPullRequestId, repoOwner, repoName, deploymentCheckId, latestPullRequest) {
        uxLog("log", this, c.grey(`[GitHub Integration] Listing comments for PR ${latestPullRequestId}`));
        const existingComments = await this.octokit.rest.issues.listComments({
            owner: repoOwner,
            repo: repoName,
            issue_number: latestPullRequestId,
        });
        for (const existingComment of existingComments.data) {
            if ((existingComment.body || "").includes("<!-- sfdx-hardis deployment-id ")) {
                const matches = /<!-- sfdx-hardis deployment-id (.*) -->/gm.exec(existingComment.body || "");
                if (matches) {
                    deploymentCheckId = matches[1];
                    uxLog("error", this, c.grey(`Found deployment id ${deploymentCheckId} on PR #${latestPullRequestId} ${latestPullRequest.title}`));
                    break;
                }
            }
        }
        return deploymentCheckId;
    }
    // Returns current job URL
    async getCurrentJobUrl() {
        if (process.env.PIPELINE_JOB_URL) {
            return process.env.PIPELINE_JOB_URL;
        }
        try {
            if (this.repoOwner && this.repoName && this.serverUrl && this.runId) {
                return `${this.serverUrl}/${this.repoOwner}/${this.repoName}/actions/runs/${this.runId}`;
            }
        }
        catch (err) {
            uxLog("warning", this, c.yellow("[GitHub Integration]" + err.message));
        }
        if (process.env.GITHUB_JOB_URL) {
            return process.env.GITHUB_JOB_URL;
        }
        return null;
    }
    // Returns current job URL
    async getCurrentBranchUrl() {
        try {
            if (this.repoOwner && this.repoName && this.serverUrl && this.branch) {
                return `${this.serverUrl}/${this.repoOwner}/${this.repoName}/tree/${this.branch}`;
            }
        }
        catch (err) {
            uxLog("warning", this, c.yellow("[GitHub Integration]" + err.message));
        }
        return null;
    }
    // GitHub supports mermaid in PR markdown
    async supportsMermaidInPrMarkdown() {
        return true;
    }
    // Find pull request info
    async getPullRequestInfo() {
        // Case when PR is found in the context
        if (this.prNumber !== null && this.repoOwner !== null) {
            const pullRequest = await this.octokit.rest.pulls.get({
                owner: this.repoOwner,
                repo: this.repoName || "",
                pull_number: this.prNumber,
            });
            // Add cross git provider properties used by sfdx-hardis
            if (pullRequest) {
                return this.completePullRequestInfo(pullRequest.data);
            }
        }
        // Case when we find PRs from a commit
        const sha = await git().revparse(["HEAD"]);
        let graphQlRes = null;
        try {
            graphQlRes = await this.octokit.graphql(`
      query associatedPRs($sha: String, $repo: String!, $owner: String!){
        repository(name: $repo, owner: $owner) {
          commit: object(expression: $sha) {
            ... on Commit {
              associatedPullRequests(first:10){
                edges{
                  node{
                    title
                    number
                    body
                    url
                    merged,
                    baseRef {
                      id
                      name
                    }
                    author {
                      login
                    }
                  }
                }
              }
            }
          }
        }
      }
    `, {
                sha: sha,
                repo: this.repoName,
                owner: this.repoOwner,
            });
        }
        catch (error) {
            uxLog("warning", this, c.yellow(`[GitHub Integration] Error while calling GraphQL Api to list PR on commit ${sha}\n${error.message}`));
        }
        if (graphQlRes?.repository?.commit?.associatedPullRequests?.edges?.length > 0) {
            const currentGitBranch = await getCurrentGitBranch();
            const candidatePullRequests = graphQlRes.repository.commit.associatedPullRequests.edges.filter((pr) => pr.node.merged === true && pr.node.baseRef.name === currentGitBranch);
            if (candidatePullRequests.length > 0) {
                return this.completePullRequestInfo(candidatePullRequests[0].node);
            }
        }
        uxLog("log", this, c.grey(`[GitHub Integration] Unable to find related Pull Request Info`));
        return null;
    }
    // Posts a note on the merge request
    async postPullRequestMessage(prMessage) {
        if (this.repoName == null || this.prNumber == null) {
            uxLog("log", this, c.grey("[GitHub Integration] No project and merge request, so no note posted..."));
            return { posted: false, providerResult: { info: "No related pull request" } };
        }
        const githubJobUrl = await this.getCurrentJobUrl();
        // Build note message
        const messageKey = prMessage.messageKey + "-" + this.workflow + "-" + this.prNumber;
        let messageBody = `**${prMessage.title || ""}**

${prMessage.message}

_Powered by [sfdx-hardis](${CONSTANTS.DOC_URL_ROOT}) from job [${this.workflow}](${githubJobUrl})_
<!-- 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("[GitHub Integration] Listing comments of Pull Request..."));
        const existingComments = await this.octokit.rest.issues.listComments({
            owner: this.repoOwner || "",
            repo: this.repoName,
            issue_number: this.prNumber,
        });
        let existingCommentId = null;
        for (const existingComment of existingComments.data) {
            if (existingComment?.body?.includes(`<!-- sfdx-hardis message-key ${messageKey} -->`)) {
                existingCommentId = existingComment.id;
            }
        }
        // Create or update MR note
        if (existingCommentId) {
            // Update existing note
            uxLog("log", this, c.grey("[GitHub Integration] Updating Pull Request Comment on GitHub..."));
            const githubCommentEditResult = await this.octokit.rest.issues.updateComment({
                owner: this.repoOwner || "",
                repo: this.repoName,
                issue_number: this.prNumber,
                comment_id: existingCommentId,
                body: messageBody,
            });
            const prResult = {
                posted: githubCommentEditResult.data.id > 0,
                providerResult: githubCommentEditResult,
            };
            return prResult;
        }
        else {
            // Create new note if no existing not was found
            uxLog("log", this, c.grey("[GitHub Integration] Adding Pull Request Comment on GitHub..."));
            const githubCommentCreateResult = await this.octokit.rest.issues.createComment({
                owner: this.repoOwner || "",
                repo: this.repoName,
                issue_number: this.prNumber,
                body: messageBody,
            });
            const prResult = {
                posted: githubCommentCreateResult.data.id > 0,
                providerResult: githubCommentCreateResult,
            };
            return prResult;
        }
    }
    completePullRequestInfo(prData) {
        const prInfo = {
            idNumber: prData?.number || 0,
            idStr: String(prData.number || ""),
            sourceBranch: (prData?.head?.ref || "").replace("refs/heads/", ""),
            targetBranch: (prData?.base?.ref || "").replace("refs/heads/", ""),
            title: prData?.title || "",
            description: prData?.body || "",
            authorName: prData?.user?.login || "",
            webUrl: prData?.html_url || "",
            providerInfo: prData,
            customBehaviors: {}
        };
        return this.completeWithCustomBehaviors(prInfo);
    }
}
//# sourceMappingURL=github.js.map