name: Validate scripts
on:
  push:
    branches:
      - main
  pull_request_target:
    paths:
      - "ct/*.sh"
      - "install/*.sh"

jobs:
  check-scripts:
    name: Check changed files
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write

    steps:
      - name: Debug event payload
        run: |
          echo "Event name: ${{ github.event_name }}"
          echo "Payload: $(cat $GITHUB_EVENT_PATH)"

      - 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
          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 }} | grep -E '\.(sh|func)$' | xargs)" >> $GITHUB_OUTPUT
          else
            echo "files=$(git diff --name-only ${{ github.event.before }} ${{ github.event.after }} | grep -E '\.(sh|func)$' | xargs)" >> $GITHUB_OUTPUT
          fi

      - name: Check build.func line
        if: always() && steps.changed-files.outputs.files != ''
        id: build-func
        run: |
          NON_COMPLIANT_FILES=""
          for FILE in ${{ steps.changed-files.outputs.files }}; do
            if [[ "$FILE" == ct/* ]] && [[ $(sed -n '2p' "$FILE") != "source <(curl -s https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)" ]]; then
              NON_COMPLIANT_FILES="$NON_COMPLIANT_FILES $FILE"
            fi
          done

          if [ -n "$NON_COMPLIANT_FILES" ]; then
            echo "files=$NON_COMPLIANT_FILES" >> $GITHUB_OUTPUT
            echo "Build.func line missing or incorrect in files:"
            for FILE in $NON_COMPLIANT_FILES; do
              echo "$FILE"
            done
            exit 1
          fi

      - name: Check executable permissions
        if: always() && steps.changed-files.outputs.files != ''
        id: check-executable
        run: |
          NON_COMPLIANT_FILES=""
          for FILE in ${{ steps.changed-files.outputs.files }}; do
            if [[ ! -x "$FILE" ]]; then
              NON_COMPLIANT_FILES="$NON_COMPLIANT_FILES $FILE"
            fi
          done

          if [ -n "$NON_COMPLIANT_FILES" ]; then
            echo "files=$NON_COMPLIANT_FILES" >> $GITHUB_OUTPUT
            echo "Files not executable:"
            for FILE in $NON_COMPLIANT_FILES; do
              echo "$FILE"
            done
            exit 1
          fi

      - name: Check copyright
        if: always() && steps.changed-files.outputs.files != ''
        id: check-copyright
        run: |
          NON_COMPLIANT_FILES=""
          for FILE in ${{ steps.changed-files.outputs.files }}; do
            if ! sed -n '3p' "$FILE" | grep -qE "^# Copyright \(c\) [0-9]{4}(-[0-9]{4})? (tteck \| community-scripts ORG|community-scripts ORG|tteck)$"; then
              NON_COMPLIANT_FILES="$NON_COMPLIANT_FILES $FILE"
            fi
          done

          if [ -n "$NON_COMPLIANT_FILES" ]; then
            echo "files=$NON_COMPLIANT_FILES" >> $GITHUB_OUTPUT
            echo "Copyright header missing or not on line 3 in files:"
            for FILE in $NON_COMPLIANT_FILES; do
              echo "$FILE"
            done
            exit 1
          fi

      - name: Check author
        if: always() && steps.changed-files.outputs.files != ''
        id: check-author
        run: |
          NON_COMPLIANT_FILES=""
          for FILE in ${{ steps.changed-files.outputs.files }}; do
            if ! sed -n '4p' "$FILE" | grep -qE "^# Author: .+"; then
              NON_COMPLIANT_FILES="$NON_COMPLIANT_FILES $FILE"
            fi
          done

          if [ -n "$NON_COMPLIANT_FILES" ]; then
            echo "files=$NON_COMPLIANT_FILES" >> $GITHUB_OUTPUT
            echo "Author header missing or invalid on line 4 in files:"
            for FILE in $NON_COMPLIANT_FILES; do
              echo "$FILE"
            done
            exit 1
          fi

      - name: Check license
        if: always() && steps.changed-files.outputs.files != ''
        id: check-license
        run: |
          NON_COMPLIANT_FILES=""
          for FILE in ${{ steps.changed-files.outputs.files }}; do
            if [[ "$(sed -n '5p' "$FILE")" != "# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE" ]]; then
              NON_COMPLIANT_FILES="$NON_COMPLIANT_FILES $FILE"
            fi
          done

          if [ -n "$NON_COMPLIANT_FILES" ]; then
            echo "files=$NON_COMPLIANT_FILES" >> $GITHUB_OUTPUT
            echo "License header missing or not on line 5 in files:"
            for FILE in $NON_COMPLIANT_FILES; do
              echo "$FILE"
            done
            exit 1
          fi

      - name: Check source
        if: always() && steps.changed-files.outputs.files != ''
        id: check-source
        run: |
          NON_COMPLIANT_FILES=""
          for FILE in ${{ steps.changed-files.outputs.files }}; do
            if ! sed -n '6p' "$FILE" | grep -qE "^# Source: .+"; then
              NON_COMPLIANT_FILES="$NON_COMPLIANT_FILES $FILE"
            fi
          done

          if [ -n "$NON_COMPLIANT_FILES" ]; then
            echo "files=$NON_COMPLIANT_FILES" >> $GITHUB_OUTPUT
            echo "Source header missing or not on line 6 in files:"
            for FILE in $NON_COMPLIANT_FILES; do
              echo "$FILE"
            done
            exit 1
          fi

      - name: Post results and comment
        if: always() && steps.changed-files.outputs.files != '' && github.event_name == 'pull_request_target'
        uses: actions/github-script@v7
        with:
          script: |
            const result = '${{ job.status }}' === 'success' ? 'success' : 'failure';
            const nonCompliantFiles = {
              'Invalid build.func source': "${{ steps.build-func.outputs.files || '' }}",
              'Not executable': "${{ steps.check-executable.outputs.files || '' }}",
              'Copyright header line missing or invalid': "${{ steps.check-copyright.outputs.files || '' }}",
              'Author header line missing or invalid': "${{ steps.check-author.outputs.files || '' }}",
              'License header line missing or invalid': "${{ steps.check-license.outputs.files || '' }}",
              'Source header line missing or invalid': "${{ steps.check-source.outputs.files || '' }}"
            };

            const issueNumber = context.payload.pull_request ? context.payload.pull_request.number : null;
            const commentIdentifier = 'validate-scripts';
            let newCommentBody = `<!-- ${commentIdentifier}-start -->\n### Script 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}:**\n`;
                  files.trim().split(' ').forEach(file => {
                    newCommentBody += `- ${file}: ${check}\n`;
                  });
                  newCommentBody += `\n`;
                }
              }
            } else {
              newCommentBody += `:rocket: All changed shell scripts passed 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.body.includes(`<!-- ${commentIdentifier}-start -->`) &&
                comment.user.login === 'github-actions[bot]'
              );

              if (existingComment) {
                const re = new RegExp(String.raw`<!-- ${commentIdentifier}-start -->[\\s\\S]*?<!-- ${commentIdentifier}-end -->`, "m");
                newCommentBody = existingComment.body.replace(re, 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
                });
              }
            }
