name: "Test random 💯"

env:
  TERM: xterm

on:
  push:
    branches: main
    paths: 'programs/x86_64/**'

  #pull_request:
  #  branches: main
  #  paths: 'programs/x86_64/**'

  workflow_dispatch:

  schedule:
    - cron: '0 23 * * *'

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: false

permissions:
  actions: write
  contents: write

jobs:
  update-testing-branch:
    name: "prepare 💤"
    runs-on: ubuntu-22.04

    steps:
      - name: "Check out repository"
        uses: actions/checkout@v4

      - name: "Git Config"
        run: |
          git config user.name "GitHub Actions Bot"
          git config user.email "actions@github.com"

      - name: "Merge main in testing if needed"
        run: |
          git fetch origin main
          git fetch origin testing || echo "Branch 'testing' does not exist, creating a new one."
          if ! git show-ref --verify --quiet refs/heads/testing; then
            git checkout -b testing origin/main
          else
            git checkout testing
          fi
          git fetch origin main
          if [[ $(git rev-list HEAD...origin/main --count) -gt 0 ]]; then
            echo "Changes detected between 'main' and 'testing'. Rebasing..."
            git merge origin/main --no-edit
            git push origin testing
          fi
          if [[ $GITHUB_REF == refs/pull/* ]]; then
            echo "This is Pull Request. No saving results."
          fi

  show-stats:
    name: "stats 📝"
    runs-on: ubuntu-22.04
    needs: update-testing-branch

    steps:
      - name: "Check out repository 🏃"
        uses: actions/checkout@v4
        with:
          ref: testing  # Work on testing branch

      - name: "Show stats 📝"
        run: |
          x64Count=$(find programs/x86_64/ -type f | wc -l)
          i68Count=$(find programs/i686/ -type f | wc -l)
          a64Count=$(find programs/aarch64/ -type f | wc -l)
          tested=$(wc -l < tested.list 2>/dev/null || echo 0)
          failed=$(wc -l < failed.list 2>/dev/null || echo 0)
          echo "### 🎬 apps" >> $GITHUB_STEP_SUMMARY
          echo "$x64Count x86_64" >> $GITHUB_STEP_SUMMARY
          echo "$i68Count i686" >> $GITHUB_STEP_SUMMARY
          echo "$a64Count aarch64" >> $GITHUB_STEP_SUMMARY
          echo "### 🔨 tests" >> $GITHUB_STEP_SUMMARY
          echo " 🏁 $tested" >> $GITHUB_STEP_SUMMARY
          echo " ❌ $failed" >> $GITHUB_STEP_SUMMARY

  generate-matrix:
    name: "matrix 🌀"
    needs: update-testing-branch
    runs-on: ubuntu-22.04
    outputs:
      matrix: ${{ steps.set-matrix.outputs.matrix }}
      count: ${{ steps.am-install.outputs.count }}
    steps:
      - name: "Check out repository 🏃"
        uses: actions/checkout@v4
        with:
          ref: testing

      - name: "Generate Matrix 🏆"
        id: set-matrix
        run: |
          mkdir -p results
          find programs/x86_64/ -maxdepth 1 -type f -printf "%f\n" | sort > all.list
          if [[ -f tested.list ]]; then
            if diff -q all.list tested.list; then
              echo "Everything already tested? Add new app or delete tested.list"
              exit 99
            else
              comm -23 all.list tested.list > totest_tmp.list
            fi
          else
            cp all.list totest_tmp.list
          fi
          if [[ -f failed.list ]]; then
            comm -23 totest_tmp.list failed.list > totest.list
            echo "Excluding failed!"
          else
            mv totest_tmp.list totest.list
          fi
          FILES=$(shuf -n 100 totest.list || cat totest.list)
          MATRIX="{\"include\": ["
          for file in $FILES; do
            MATRIX+="{\"file\": \"$file\"},"
          done
          MATRIX="${MATRIX%,}]}"
          echo "matrix=$MATRIX" >> $GITHUB_OUTPUT

  run-actions:
    name: "🔨"
    needs: generate-matrix
    runs-on: ubuntu-22.04
    strategy:
      fail-fast: false
      matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }}
    env:
      TIMEOUT: 10
    steps:
      - name: "Check out repository 🏃"
        uses: actions/checkout@v4
        with:
          ref: testing

      - name: "Install dependencies 📦️"
        run: |
          sudo apt-get -y update 2> /dev/null || apt-get -y update
          sudo apt-get -y install wget curl torsocks zsync 2> /dev/null || apt-get -y install git wget curl torsocks zsync

      - name: "Install AM 🎁"
        run: |
          mkdir -p results /usr/local/bin
          chmod +x ./INSTALL
          sudo ./INSTALL 2> /dev/null || ./INSTALL

      - name: "test ${{ matrix.file }} 🚧"
        run: |
          set -uo pipefail
          mkdir -p results
          script_content=$(curl -Ls https://raw.githubusercontent.com/ivan-hc/AM/main/programs/x86_64/"${{ matrix.file }}")
          pure_arg=$(echo "${{ matrix.file }}" | sed 's/\.appimage//g; s/\^debian-testing-//g; s/\-appimage$//g' | sed 's:.*/::')
          to_failed() {
            echo "${{ matrix.file }}" > results/ko-${{ matrix.file }}
          }
          if timeout "$TIMEOUT"m am -i "${{ matrix.file }}" --debug 2>&1 | tee -a results/log-"${{ matrix.file }}"; then
            echo ""
            echo " Structure of the directory in /opt"
            echo ""
            if test -d /opt/kdegames; then
               ls /opt/kdegames | tee -a results/log-"${{ matrix.file }}"
            elif test -d /opt/kdeutils; then
               ls /opt/kdeutils | tee -a results/log-"${{ matrix.file }}"
            elif test -d /opt/platform-tools; then
               ls /opt/platform-tools | tee -a results/log-"${{ matrix.file }}"
            elif test -d /opt/"$pure_arg"; then
               ls /opt/"$pure_arg" | tee -a results/log-"${{ matrix.file }}"
            elif [ "$pure_arg" = avidemux ]; then
               echo /opt/avidemux | tee -a results/log-"${{ matrix.file }}"
            elif [[ "$pure_arg" =~ (code|deadbeef*|libfuse2|libreoffice|microsoft-edge*|mpv|node|npm|swift|wine) ]]; then
               echo "App not installed, this is a Known error related to GitHub Actions" | tee -a results/log-"${{ matrix.file }}"
               OK="1"
            elif test -d /opt/"$pure_arg"*; then
               ls /opt/"$pure_arg"* | tee -a results/log-"${{ matrix.file }}"
            elif echo "$script_content" | grep -q "spooky"; then
               echo "App not installed because marked as \"spooky\", require to be tested manually" | tee -a results/log-"${{ matrix.file }}"
               OK="1"
            else
               ls /opt/"${{ matrix.file }}" | tee -a results/log-"${{ matrix.file }}"
            fi
            echo ""
            echo "-------------------------------------------------------------"
            echo ""
            echo " Command in \$PATH"
            echo ""
            command -v "$pure_arg" | tee -a results/log-"${{ matrix.file }}" || ls /usr/local/bin | tee -a results/log-"${{ matrix.file }}"
            echo ""
            echo "-------------------------------------------------------------"
            echo ""
            echo " Launchers in /usr/local/share/applications" | tee -a results/log-"${{ matrix.file }}"
            echo ""
            if test -f /usr/local/share/applications/*AM.desktop 2>/dev/null; then
               ls /usr/local/share/applications | grep "AM.desktop$" | tee -a results/log-"${{ matrix.file }}"
            else
               ls /usr/local/share/applications | tee -a results/log-"${{ matrix.file }}"
            fi
            echo ""
            echo "-------------------------------------------------------------"
            am -R "${{ matrix.file }}" && echo "${{ matrix.file }}" > results/ok-${{ matrix.file }} || [ "OK" =1 ] && echo "${{ matrix.file }}" > results/ok-${{ matrix.file }} || to_failed
          else
            if [[ $? -eq 124 ]]; then
               echo "### 💥 ${{ matrix.file }} timeout!" >> $GITHUB_STEP_SUMMARY
               echo "Installation timeout in 10 minutes" >> results/log-"${{ matrix.file }}"
               to_failed
            else
               echo "### 💀 ${{ matrix.file }}" >> $GITHUB_STEP_SUMMARY
               to_failed
            fi
            exit 1
          fi

      - name: "Upload Failed Results ☝️"
        if: failure()
        uses: actions/upload-artifact@v4
        with:
          name: ko-${{ matrix.file }}
          path: results/ko-${{ matrix.file }}

      - name: "Upload Log Results ☝️"
        if: failure()
        uses: actions/upload-artifact@v4
        with:
          name: log-${{ matrix.file }}
          path: results/log-${{ matrix.file }}

      - name: "Upload Test Results ⬆️"
        if: success()
        uses: actions/upload-artifact@v4
        with:
          name: ok-${{ matrix.file }}
          path: results/ok-${{ matrix.file }}

  update-tested-list:
    name: "results 📰"
    needs: run-actions
    runs-on: ubuntu-22.04
    if: always()
    steps:
      - name: "Check out repository 🏃"
        uses: actions/checkout@v4
        with:
          ref: testing

      - name: "Download Test Results ⬇️"
        uses: actions/download-artifact@v4
        with:
          path: results
          merge-multiple: true
      - run: ls -R results

      - name: "Git Config"
        run: |
          git config user.name "github-actions[bot]"
          git config user.email "41898282+github-actions[bot]@users.noreply.github.com"

      - name: "Aggregate and push results"
        run: |
          ls -R results
          #git checkout -b testing
          #git push --set-upstream origin testing
          if compgen -G "results/ok-*" > /dev/null; then
            for file in results/ok-*; do
              cat "$file" >> aggregated.list
            done
            cat aggregated.list >> tested.list
            sort -u tested.list -o tested.list
            git add tested.list
          else
            echo "Nothing tested successfully?"
          fi
          if compgen -G "results/ko-*" > /dev/null; then
            for file in results/ko-*; do
              cat "$file" >> fail.list
            done
            mkdir -p logs
            cp results/log-* logs/
            fail=$(wc -l < fail.list)
            cat fail.list >> failed.list
            sort -u failed.list -o failed.list
            git add failed.list logs
          else
            echo "Nothing failed? Great!"
            fail="0"
          fi
          if git diff --cached --quiet; then
            echo "No changes to commit?"
          else
            if [[ $GITHUB_REF == refs/pull/* ]]; then
              echo "This is Pull Request. No saving results."
            else
              git commit -m "update results"
              git push origin testing
            fi
          fi

      - name: "Show Results 🏁"
        if: always()
        run: |
          tested=$(wc -l < tested.list 2>/dev/null || echo 0)
          failed=$(wc -l < failed.list 2>/dev/null || echo 0)
          fail=$(wc -l < fail.list 2>/dev/null || echo "0")
          count=$(find programs/x86_64/ -type f | wc -l)
          remaining=$((count - tested))
          echo "### 🏁 $tested tested" >> $GITHUB_STEP_SUMMARY
          echo "## 🛅 $remaining to test" >> $GITHUB_STEP_SUMMARY
          echo "😱 $failed fails listed" >> $GITHUB_STEP_SUMMARY
          echo ":x: $fail failed now" >> $GITHUB_STEP_SUMMARY

  delete-all-artifacts:
    name: "cleanup 🧹"
    runs-on: ubuntu-22.04
    needs: update-tested-list
    if: always()
    steps:
      - name: "Check out repository 🏃"
        uses: actions/checkout@v4

      - name: "Delete Artifacts 🙈"
        env:
          REPO_NAME: ${{ github.repository }}
          RUN_ID: ${{ github.run_id }}
          TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          echo "Fetching and deleting all artifacts for run ID: $RUN_ID"
          PAGE=1
          DELETED=0
          while true; do
            RESPONSE=$(curl -s -H "Authorization: token $TOKEN" \
             "https://api.github.com/repos/$REPO_NAME/actions/runs/$RUN_ID/artifacts?per_page=100&page=$PAGE")
            ARTIFACT_IDS=$(echo "$RESPONSE" | jq -r '.artifacts[].id')
            if [[ -z "$ARTIFACT_IDS" ]]; then
              echo "No more artifacts to delete. Total deleted: $DELETED"
              break
            fi
            for ARTIFACT_ID in $ARTIFACT_IDS; do
              echo "Deleting artifact with ID: $ARTIFACT_ID"
              curl -X DELETE -s -H "Authorization: token $TOKEN" \
               "https://api.github.com/repos/$REPO_NAME/actions/artifacts/$ARTIFACT_ID"
              ((DELETED+=1))
            done
            ((PAGE+=1))
          done
          echo "Successfully deleted $DELETED artifacts."
