name: "Build"
on:
  pull_request:
  push:
    branches:
      - main
      - dev
      - "feature/**"
      - "release/**"
      - "hotfix/**"
  workflow_dispatch:

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: true
      matrix:
        php-versions: ["8.3", "8.4", "8.5"]
    name: PHP ${{ matrix.php-versions }}
    env:
      extensions: intl, pcov, mbstring
      key: cache-v1
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      # https://github.com/marketplace/actions/nerdbank-gitversioning
      - name: Nerdbank.GitVersioning
        uses: dotnet/nbgv@v0.4.2
        with:
          setAllVars: true

      # Configure Caching
      - name: Setup cache environment
        id: cache-env
        uses: shivammathur/cache-extensions@v1
        with:
          php-version: ${{ matrix.php-versions }}
          extensions: ${{ env.extensions }}
          key: ${{ env.key }}

      - name: Cache extensions
        uses: actions/cache@v4
        with:
          path: ${{ steps.cache-env.outputs.dir }}
          key: ${{ steps.cache-env.outputs.key }}
          restore-keys: ${{ steps.cache-env.outputs.key }}

      - name: Get composer cache directory
        id: composer-cache
        run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT

      - name: Cache dependencies
        uses: actions/cache@v4
        with:
          path: ${{ steps.composer-cache.outputs.dir }}
          key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}

      # Configure PHP
      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: ${{ matrix.php-versions }}
          extensions: ${{ env.extensions }}
          ini-values: post_max_size=256M, short_open_tag=On
          coverage: xdebug
          tools: php-cs-fixer, phpunit

      # Bootstrap order has to thread a needle:
      #   1. composer install --no-scripts: pulls vendor/ (needed by Vite
      #      because theme.css @imports vendor/filament/filament/resources/css)
      #      WITHOUT firing post-autoload-dump (which boots service providers
      #      that read the Vite manifest + dist files we haven't built yet).
      #   2. npm install + npm run build: produces public/build/manifest.json
      #      and (re)writes resources/js/dist/admin/components/*.js.
      #   3. composer dump-autoload: re-fires post-autoload-dump now that the
      #      frontend artifacts exist; package:discover and filament:upgrade
      #      boot providers cleanly.
      - name: Install Composer dependencies (no scripts)
        run: |
          php --version
          composer install --dev --no-interaction --no-scripts --verbose
          composer global require laravel/pint

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: "npm"

      - name: Install NPM dependencies
        run: |
          npm install
          npm run fmt config/version.yml
        # Need to lint version.yml since it’s updated in CI

      - name: Lint & Format Check
        run: npm run lint && npm run fmt:check

      - name: Compile assets
        run: npm run build

      - name: Run Composer post-autoload scripts
        run: |
          composer dump-autoload -o
          cp .github/scripts/env.test .env
          cp .github/scripts/phpunit.xml phpunit.xml
          .github/scripts/version.sh

      - name: Run Pint
        run: pint --test --parallel

      - name: Run Tests
        run: |
          export PHP_CS_FIXER_IGNORE_ENV=1
          vendor/bin/pest --parallel --ci

      - name: Run PHPStan
        run: vendor/bin/phpstan analyse --memory-limit=2G

  #     - name: Run Rector
  #       run: |
  #         vendor/bin/rector --dry-run

  # This runs after all of the tests, run have run. Creates a cleaned up version of the
  # distro, and then creates the artifact to push up to S3 or wherever
  artifacts:
    name: "Create release package"
    permissions:
      contents: write
      packages: write
      attestations: write
      id-token: write
    needs: [build]
    runs-on: ubuntu-latest
    if: github.repository == 'phpvms/phpvms' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev')
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      # https://github.com/marketplace/actions/nerdbank-gitversioning
      - name: Nerdbank.GitVersioning
        uses: dotnet/nbgv@v0.4.2
        with:
          setAllVars: true

      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: "8.3"

      - uses: olegtarasov/get-tag@v2.1.2
        id: tagName

      # Configure Caching
      - name: Get composer cache directory
        id: composer-cache
        run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT

      - name: Cache dependencies
        uses: actions/cache@v4
        with:
          path: ${{ steps.composer-cache.outputs.dir }}
          key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
          restore-keys: ${{ runner.os }}-composer-

      # Three-step bootstrap (see `build` job comment for full rationale):
      #   1. composer install --no-scripts: vendor/ for Vite CSS @imports
      #   2. npm build: writes public/build manifest + dist files
      #   3. composer dump-autoload: re-fires post-autoload-dump cleanly
      - name: "Install Release Dependencies (no scripts)"
        run: |
          rm -rf vendor
          composer install --no-dev --prefer-dist --no-interaction --no-scripts --verbose
          sudo chmod +x ./.github/scripts/*

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: "npm"

      - name: Install NPM dependencies
        run: npm install

      - name: Compile assets
        run: npm run build

      - name: Run Composer post-autoload scripts
        run: composer dump-autoload

      - id: version
        name: Get version
        run: .github/scripts/version.sh

      - name: Build Distro
        run: .github/scripts/build.sh

      - uses: BetaHuhn/do-spaces-action@v2
        id: spaces
        with:
          access_key: ${{ secrets.SPACE_ACCESS_KEY}}
          secret_key: ${{ secrets.SPACE_SECRET_KEY }}
          space_name: ${{ secrets.SPACE_NAME }}
          space_region: ${{ secrets.SPACE_REGION }}
          source: dist
          cdn_domain: phpvms.cdn.vmslabs.net
          permission: public-read

      - name: Discord notification
        uses: Ilshidur/action-discord@0.3.2
        env:
          DISCORD_WEBHOOK: ${{ secrets.V8_DISCORD_WEBHOOK }}
        with:
          args: ${{ steps.version.outputs.discord_msg }}

      - name: Upload artifact for deployment job
        uses: actions/upload-artifact@v4
        with:
          name: phpvms-package
          path: "dist/*"

  docker:
    name: "Create docker image"
    permissions:
      contents: write
      packages: write
      attestations: write
      id-token: write
    runs-on: ubuntu-latest
    needs: [build]
    if: github.repository == 'phpvms/phpvms' && github.event_name != 'pull_request' && (github.ref == 'refs/heads/main')
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      # Configure Caching
      - name: Get composer cache directory
        id: composer-cache
        run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT

      - name: Cache dependencies
        uses: actions/cache@v4
        with:
          path: ${{ steps.composer-cache.outputs.dir }}
          key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
          restore-keys: ${{ runner.os }}-composer-

      # Three-step bootstrap (see `build` job comment for full rationale):
      #   1. composer install --no-scripts: vendor/ for Vite CSS @imports
      #   2. npm build: writes public/build manifest + dist files
      #   3. composer dump-autoload: re-fires post-autoload-dump cleanly
      - name: "Install Release Dependencies (no scripts)"
        run: |
          rm -rf vendor
          composer install --no-dev --prefer-dist --no-interaction --no-scripts --verbose
          sudo chmod +x ./.github/scripts/*

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: "npm"

      - name: Install NPM dependencies
        run: npm install

      - name: Compile assets
        run: npm run build

      - name: Run Composer post-autoload scripts
        run: composer dump-autoload

      # https://github.com/marketplace/actions/nerdbank-gitversioning
      - name: Nerdbank.GitVersioning
        uses: dotnet/nbgv@v0.4.2
        with:
          setAllVars: true

      - id: version
        name: Get version
        run: .github/scripts/version.sh

      - name: Login to GitHub Container Registry
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Docker meta
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          tags: |
            type=semver,pattern={{version}},value=${{ env.NBGV_SemVer2 }}
            type=semver,pattern={{major}}.{{minor}},value=${{ env.NBGV_SemVer2 }}
            type=ref,event=branch

      - name: Build and push
        id: push
        uses: docker/build-push-action@v6
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}

      - name: Generate artifact attestation
        uses: actions/attest-build-provenance@v2
        with:
          subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}}
          subject-digest: ${{ steps.push.outputs.digest }}
          push-to-registry: true
