name: Validate filenames

on:
  pull_request_target:
    paths:
      - "ct/*.sh"
      - "install/*.sh"
      - "frontend/public/json/*.json"

jobs:
  check-files:
    if: github.repository == 'community-scripts/ProxmoxVE'
    name: Check changed files
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write

    steps:
      - name: Get pull request information
        if: github.event_name == 'pull_request_target'
        uses: actions/github-script@v7
        id: pr
        with:
          script: |
            const { data: pullRequest } = await github.rest.pulls.get({
              ...context.repo,
              pull_number: context.payload.pull_request.number,
            });
            return pullRequest;

      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0 # Ensure the full history is fetched for accurate diffing
          ref: ${{ github.event_name == 'pull_request_target' && fromJSON(steps.pr.outputs.result).merge_commit_sha || '' }}

      - name: Get changed files
        id: changed-files
        run: |
          if ${{ github.event_name == 'pull_request_target' }}; then
              echo "files=$(git diff --name-only ${{ github.event.pull_request.base.sha }} ${{ steps.pr.outputs.result && fromJSON(steps.pr.outputs.result).merge_commit_sha }} | xargs)" >> $GITHUB_OUTPUT
          else
              echo "files=$(git diff --name-only ${{ github.event.before }} ${{ github.event.after }} | xargs)" >> $GITHUB_OUTPUT
          fi

      - name: "Validate filenames in ct and install directory"
        if: always() && steps.changed-files.outputs.files != ''
        id: check-scripts
        run: |
          CHANGED_FILES=$(printf "%s\n" ${{ steps.changed-files.outputs.files }} | { grep -E '^(ct|install)/.*\.sh$' || true; })

          NON_COMPLIANT_FILES=""
          for FILE in $CHANGED_FILES; do
            BASENAME=$(echo "$(basename "${FILE%.*}")")
            if [[ ! "$BASENAME" =~ ^[a-z0-9-]+$ ]]; then
              NON_COMPLIANT_FILES="$NON_COMPLIANT_FILES $FILE"
            fi
          done

          if [ -n "$NON_COMPLIANT_FILES" ]; then
            echo "files=$NON_COMPLIANT_FILES" >> $GITHUB_OUTPUT
            echo "Non-compliant filenames found, change to lowercase:"
            for FILE in $NON_COMPLIANT_FILES; do
              echo "$FILE"
            done
            exit 1
          fi

      - name: "Validate filenames in json directory."
        if: always() && steps.changed-files.outputs.files != ''
        id: check-json
        run: |
          CHANGED_FILES=$(printf "%s\n" ${{ steps.changed-files.outputs.files }} | { grep -E '^json/.*\.json$' || true; })

          NON_COMPLIANT_FILES=""
          for FILE in $CHANGED_FILES; do
            BASENAME=$(echo "$(basename "${FILE%.*}")")
            if [[ ! "$BASENAME" =~ ^[a-z0-9-]+$ ]]; then
                    NON_COMPLIANT_FILES="$NON_COMPLIANT_FILES $FILE"
            fi
          done

          if [ -n "$NON_COMPLIANT_FILES" ]; then
            echo "files=$NON_COMPLIANT_FILES" >> $GITHUB_OUTPUT
            echo "Non-compliant filenames found, change to lowercase:"
            for FILE in $NON_COMPLIANT_FILES; do
              echo "$FILE"
            done
            exit 1
          fi

      - name: Post results and comment
        if: always() && steps.check-scripts.outputs.files != '' && steps.check-json.outputs.files != '' && github.event_name == 'pull_request_target'
        uses: actions/github-script@v7
        with:
          script: |
            const result = "${{ job.status }}" === "success" ? "success" : "failure";
            const nonCompliantFiles = {
              script: "${{ steps.check-scripts.outputs.files }}",
              JSON: "${{ steps.check-json.outputs.files }}",
            };

            const issueNumber = context.payload.pull_request
              ? context.payload.pull_request.number
              : null;
            const commentIdentifier = "validate-filenames";
            let newCommentBody = `<!-- ${commentIdentifier}-start -->\n### Filename validation\n\n`;

            if (result === "failure") {
              newCommentBody += ":x: We found issues in the following changed files:\n\n";
              for (const [check, files] of Object.entries(nonCompliantFiles)) {
                if (files) {
                  newCommentBody += `**${check.charAt(0).toUpperCase() + check.slice(1)} filename invalid:**\n${files
                    .trim()
                    .split(" ")
                    .map((file) => `- ${file}`)
                    .join("\n")}\n\n`;
                }
              }
              newCommentBody +=
                "Please change the filenames to lowercase and use only alphanumeric characters and dashes.\n";
            } else {
              newCommentBody += `:rocket: All files passed filename validation!\n`;
            }

            newCommentBody += `\n\n<!-- ${commentIdentifier}-end -->`;

            if (issueNumber) {
              const { data: comments } = await github.rest.issues.listComments({
                ...context.repo,
                issue_number: issueNumber,
              });

              const existingComment = comments.find(
                (comment) => comment.user.login === "github-actions[bot]",
              );

              if (existingComment) {
                if (existingComment.body.includes(commentIdentifier)) {
                  const re = new RegExp(String.raw`<!-- ${commentIdentifier}-start -->[\s\S]*?<!-- ${commentIdentifier}-end -->`, "");
                  newCommentBody = existingComment.body.replace(re, newCommentBody);
                } else {
                  newCommentBody = existingComment.body + '\n\n---\n\n' + newCommentBody;
                }

                await github.rest.issues.updateComment({
                  ...context.repo,
                  comment_id: existingComment.id,
                  body: newCommentBody,
                });
              } else {
                await github.rest.issues.createComment({
                  ...context.repo,
                  issue_number: issueNumber,
                  body: newCommentBody,
                });
              }
            }
