name: Check Properties Files on PR

on:
  pull_request_target:
    types: [opened, synchronize, reopened]
    paths:
      - "stirling-pdf/src/main/resources/messages_*.properties"

permissions:
  contents: read # Allow read access to repository content

jobs:
  check-files:
    if: github.event_name == 'pull_request_target'
    runs-on: ubuntu-latest
    permissions:
      issues: write # Allow posting comments on issues/PRs
      pull-requests: write # Allow writing to pull requests
    steps:
      - name: Harden Runner
        uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0
        with:
          egress-policy: audit

      - name: Checkout main branch first
        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

      - name: Setup GitHub App Bot
        id: setup-bot
        uses: ./.github/actions/setup-bot
        with:
          app-id: ${{ secrets.GH_APP_ID }}
          private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}

      - name: Get PR data
        id: get-pr-data
        uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
        with:
          github-token: ${{ steps.setup-bot.outputs.token }}
          script: |
            const prNumber = context.payload.pull_request.number;
            const repoOwner = context.payload.repository.owner.login;
            const repoName = context.payload.repository.name;
            const branch = context.payload.pull_request.head.ref;

            console.log(`PR Number: ${prNumber}`);
            console.log(`Repo Owner: ${repoOwner}`);
            console.log(`Repo Name: ${repoName}`);
            console.log(`Branch: ${branch}`);

            core.setOutput("pr_number", prNumber);
            core.setOutput("repo_owner", repoOwner);
            core.setOutput("repo_name", repoName);
            core.setOutput("branch", branch);
        continue-on-error: true

      - name: Fetch PR changed files
        id: fetch-pr-changes
        env:
          GH_TOKEN: ${{ steps.setup-bot.outputs.token }}
        run: |
          echo "Fetching PR changed files..."
          echo "Getting list of changed files from PR..."
                   # Check if PR number exists
            if [ -z "${{ steps.get-pr-data.outputs.pr_number }}" ]; then
              echo "Error: PR number is empty"
              exit 1
            fi
            # Get changed files and filter for properties files, handle case where no matches are found
            gh pr view ${{ steps.get-pr-data.outputs.pr_number }} --json files -q ".files[].path" | grep -E '^stirling-pdf/src/main/resources/messages_[a-zA-Z_]{2}_[a-zA-Z_]{2,7}\.properties$' > changed_files.txt || echo "No matching properties files found in PR"
            # Check if any files were found
            if [ ! -s changed_files.txt ]; then
              echo "No properties files changed in this PR"
              echo "Workflow will exit early as no relevant files to check"
              exit 0
            fi
            echo "Found $(wc -l < changed_files.txt) matching properties files"

      - name: Determine reference file test
        id: determine-file
        uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
        with:
          github-token: ${{ steps.setup-bot.outputs.token }}
          script: |
            const fs = require("fs");
            const path = require("path");

            const prNumber = ${{ steps.get-pr-data.outputs.pr_number }};
            const repoOwner = "${{ steps.get-pr-data.outputs.repo_owner }}";
            const repoName = "${{ steps.get-pr-data.outputs.repo_name }}";

            const prRepoOwner = "${{ github.event.pull_request.head.repo.owner.login }}";
            const prRepoName = "${{ github.event.pull_request.head.repo.name }}";
            const branch = "${{ steps.get-pr-data.outputs.branch }}";

            console.log(`Determining reference file for PR #${prNumber}`);

            // Validate inputs
            const validateInput = (input, regex, name) => {
              if (!regex.test(input)) {
                throw new Error(`Invalid ${name}: ${input}`);
              }
            };

            validateInput(repoOwner, /^[a-zA-Z0-9_-]+$/, "repository owner");
            validateInput(repoName, /^[a-zA-Z0-9._-]+$/, "repository name");
            validateInput(branch, /^[a-zA-Z0-9._/-]+$/, "branch name");

            // Get the list of changed files in the PR
            const { data: files } = await github.rest.pulls.listFiles({
              owner: repoOwner,
              repo: repoName,
              pull_number: prNumber,
            });

            // Filter for relevant files based on the PR changes
            const changedFiles = files
              .map(file => file.filename)
              .filter(file => /^stirling-pdf\/src\/main\/resources\/messages_[a-zA-Z_]{2}_[a-zA-Z_]{2,7}\.properties$/.test(file));

            console.log("Changed files:", changedFiles);

            // Create a temporary directory for PR files
            const tempDir = "pr-branch";
            if (!fs.existsSync(tempDir)) {
              fs.mkdirSync(tempDir, { recursive: true });
            }

            // Download and save each changed file
            for (const file of changedFiles) {
              const { data: fileContent } = await github.rest.repos.getContent({
                owner: prRepoOwner,
                repo: prRepoName,
                path: file,
                ref: branch,
              });

              const content = Buffer.from(fileContent.content, "base64").toString("utf-8");
              const filePath = path.join(tempDir, file);
              const dirPath = path.dirname(filePath);

              if (!fs.existsSync(dirPath)) {
                fs.mkdirSync(dirPath, { recursive: true });
              }

              fs.writeFileSync(filePath, content);
              console.log(`Saved file: ${filePath}`);
            }

            // Output the list of changed files for further processing
            const fileList = changedFiles.join(" ");
            core.exportVariable("FILES_LIST", fileList);
            console.log("Files saved and listed in FILES_LIST.");

            // Determine reference file
            let referenceFilePath;
            if (changedFiles.includes("stirling-pdf/src/main/resources/messages_en_GB.properties")) {
              console.log("Using PR branch reference file.");
              const { data: fileContent } = await github.rest.repos.getContent({
                owner: prRepoOwner,
                repo: prRepoName,
                path: "stirling-pdf/src/main/resources/messages_en_GB.properties",
                ref: branch,
              });

              referenceFilePath = "pr-branch-messages_en_GB.properties";
              const content = Buffer.from(fileContent.content, "base64").toString("utf-8");
              fs.writeFileSync(referenceFilePath, content);
            } else {
              console.log("Using main branch reference file.");
              const { data: fileContent } = await github.rest.repos.getContent({
                owner: repoOwner,
                repo: repoName,
                path: "stirling-pdf/src/main/resources/messages_en_GB.properties",
                ref: "main",
              });

              referenceFilePath = "main-branch-messages_en_GB.properties";
              const content = Buffer.from(fileContent.content, "base64").toString("utf-8");
              fs.writeFileSync(referenceFilePath, content);
            }

            console.log(`Reference file path: ${referenceFilePath}`);
            core.exportVariable("REFERENCE_FILE", referenceFilePath);

      - name: Run Python script to check files
        id: run-check
        run: |
          echo "Running Python script to check files..."
          python .github/scripts/check_language_properties.py \
            --actor ${{ github.event.pull_request.user.login }} \
            --reference-file "${REFERENCE_FILE}" \
            --branch "pr-branch" \
            --files "${FILES_LIST[@]}" > result.txt
        continue-on-error: true # Continue the job even if this step fails

      - name: Capture output
        id: capture-output
        run: |
          if [ -f result.txt ] && [ -s result.txt ]; then
            echo "Test, capturing output..."
            SCRIPT_OUTPUT=$(cat result.txt)
            echo "SCRIPT_OUTPUT<<EOF" >> $GITHUB_ENV
            echo "$SCRIPT_OUTPUT" >> $GITHUB_ENV
            echo "EOF" >> $GITHUB_ENV
            echo "${SCRIPT_OUTPUT}"

            # Determine job failure based on script output
            if [[ "$SCRIPT_OUTPUT" == *"❌"* ]]; then
              echo "FAIL_JOB=true" >> $GITHUB_ENV
            else
              echo "FAIL_JOB=false" >> $GITHUB_ENV
            fi
          else
            echo "No update found."
            echo "SCRIPT_OUTPUT=" >> $GITHUB_ENV
            echo "FAIL_JOB=false" >> $GITHUB_ENV
          fi

      - name: Post comment on PR
        if: env.SCRIPT_OUTPUT != ''
        uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
        with:
          github-token: ${{ steps.setup-bot.outputs.token }}
          script: |
            const { GITHUB_REPOSITORY, SCRIPT_OUTPUT } = process.env;
            const [repoOwner, repoName] = GITHUB_REPOSITORY.split('/');
            const issueNumber = context.issue.number;

            // Find existing comment
            const comments = await github.rest.issues.listComments({
              owner: repoOwner,
              repo: repoName,
              issue_number: issueNumber
            });

            const comment = comments.data.find(c => c.body.includes("## 🚀 Translation Verification Summary"));

            // Only update or create comments by the action user
            const expectedActor = "${{ steps.setup-bot.outputs.app-slug }}[bot]";

            if (comment && comment.user.login === expectedActor) {
              // Update existing comment
              await github.rest.issues.updateComment({
                owner: repoOwner,
                repo: repoName,
                comment_id: comment.id,
                body: `## 🚀 Translation Verification Summary\n\n\n${SCRIPT_OUTPUT}\n`
              });
              console.log("Updated existing comment.");
            } else if (!comment) {
              // Create new comment if no existing comment is found
              await github.rest.issues.createComment({
                owner: repoOwner,
                repo: repoName,
                issue_number: issueNumber,
                body: `## 🚀 Translation Verification Summary\n\n\n${SCRIPT_OUTPUT}\n`
              });
              console.log("Created new comment.");
            } else {
              console.log("Comment update attempt denied. Actor does not match.");
            }

      - name: Fail job if errors found
        if: env.FAIL_JOB == 'true'
        run: |
          echo "Failing the job because errors were detected."
          exit 1
