#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

name: Label Issue

on:
  issues:
    types:
      - opened
      - reopened
      - edited

concurrency:
  group: label-issue-${{ github.event.issue.number }}
  cancel-in-progress: true

permissions:
  contents: read
  issues: write

jobs:
  label-issue:
    if: "github.repository == 'apache/camel-quarkus' &&
         !contains(github.event.issue.labels.*.name, 'autolabel/ignore') &&
         !contains(github.event.issue.labels.*.name, 'build/camel-main') &&
         !contains(github.event.issue.labels.*.name, 'build/quarkus-main')"
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Code
        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
        with:
          ref: main
      - name: Install js-yaml package
        run: |
          npm install js-yaml
      - name: Label Issue
        uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
        with:
          script: |
            const fs = require('fs');
            const yaml = require('js-yaml');

            const issue = context.payload.issue;
            const labels = new Set();

            // Some common words to not directly match against
            const commonWords = ['github', 'http'];

            // Read the auto labelling configuration
            const config = yaml.load(fs.readFileSync(`./.github/auto-label-configuration.yaml`), 'utf8');

            // Lazy way of getting the names of extensions without having to search the Camel catalog etc
            const files = fs.readdirSync(`./docs/modules/ROOT/pages/reference/extensions/`);
            files.forEach(file => {
              if (!file.includes("core")) {
                let extension = file.replace(".adoc", "");

                // Build up regexes for each extension
                let regex = `\\b(?:(?:camel-)(?:quarkus-)?${extension}(?!-))\\b|\\s${extension}\\sextension`
                if (!commonWords.includes(extension)) {
                  regex += `|\\s${extension}\\s|^${extension}(?::)?\\s|\\s${extension}$`;
                }

                config['config']['auto-label'].push({
                  "regex": regex,
                  "labels": ["area/" + extension],
                  "matchOn": "title",
                });
              }
            });

            // Sanitize the issue title and body
            let sanitizedTitle = null;
            if (issue.title) {
              sanitizedTitle = issue.title.toLowerCase();
            }

            let sanitizedBody = null;
            if (issue.body) {
              // Markdown code blocks are removed, as they can provide false positives for label matching
              sanitizedBody = issue.body.toLowerCase().replace(/`{1,3}[\s\S]*?`{1,3}/g, '');
            }

            // Determine which labels should be applied to the issue
            config['config']['auto-label'].forEach(labelCandidate => {
              // Check issue title content matching configured expressions
              if (sanitizedTitle && (labelCandidate.matchOn === "title" || labelCandidate.matchOn === "titleBody")) {
                if (sanitizedTitle.match(new RegExp(labelCandidate.regex, 'gi'))) {
                  labelCandidate.labels.forEach(label => labels.add(label));
                }
              }

              // Check issue body content matching configured expressions
              if (sanitizedBody && (labelCandidate.matchOn === "body" || labelCandidate.matchOn === "titleBody")) {
                if (sanitizedBody.match(new RegExp(labelCandidate.regex, 'gi'))) {
                  labelCandidate.labels.forEach(label => labels.add(label));
                }
              }
            });

            // Filter potentially stale existing issue labels and keep any custom user added ones
            const prefixes = new Set();
            config['config']['auto-label']
              .flatMap(labelConfig => labelConfig.labels)
              .filter(label => label.includes('/'))
              .map(label => label.split('/')[0])
              .forEach(prefix => prefixes.add(prefix));

            const prefixRegex = Array.from(prefixes).join('|');
            issue.labels
              .filter(label => label.name.match("^(?!" + prefixRegex + ").*"))
              .map(label => label.name)
              .forEach(label => labels.add(label));

            // If we are not going to be adding any new labels then just exit the script
            if (labels.size === issue.labels.length) {
              const diffLabels = issue.labels.filter(label => !labels.has(label.name));
              if (diffLabels.length === 0) {
                return;
              }
            }

            // Check to see if labels already exist, and if not, create them so we can set the color
            const existingLabels = await github.paginate(
              `GET /repos/${context.repo.owner}/${context.repo.repo}/labels`,
              { owner: context.repo.owner, name: context.repo.repo },
              (response) => response.data.map((label) => label.name)
            );

            if (existingLabels) {
              for (let label of labels) {
                if (!existingLabels.includes(label)) {
                  let labelColor = 'ededed';
                  if (label.startsWith("area/")) {
                    labelColor = '283482';
                  }

                  if (label.startsWith("platform/")) {
                    labelColor = '7baaa4';
                  }

                  if (label.startsWith("release/")) {
                    labelColor = '947593'
                  }

                  await github.rest.issues.createLabel({
                    owner: context.repo.owner,
                    repo: context.repo.repo,
                    name: label,
                    color: labelColor,
                  });
                }
              };
            }

            // Update issue labels
            await github.rest.issues.setLabels({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: issue.number,
              labels: Array.from(labels)
            });
