# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: MokoStandards.CI
# REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Generic
# PATH: /.gitea/workflows/ci-generic.yml
# VERSION: 01.00.00
# BRIEF: CI pipeline — lint, validate, and test for generic projects (PHP + Node.js)

name: "Generic: Project CI"

on:
  push:
    branches:
      - main
      - dev
      - dev/**
      - rc/**
      - version/**
  pull_request:
    branches:
      - main
      - dev
      - dev/**
      - rc/**
  workflow_dispatch:

permissions:
  contents: read

env:
  FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true

jobs:
  # ── Lint & Validate ───────────────────────────────────────────────────
  lint:
    name: Lint & Validate
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Detect toolchain
        id: detect
        run: |
          HAS_PHP=false
          HAS_NODE=false
          [ -f "composer.json" ] && HAS_PHP=true
          [ -f "package.json" ] && HAS_NODE=true
          echo "has_php=$HAS_PHP" >> "$GITHUB_OUTPUT"
          echo "has_node=$HAS_NODE" >> "$GITHUB_OUTPUT"
          echo "Toolchain: PHP=$HAS_PHP Node=$HAS_NODE"

      - name: Setup PHP
        if: steps.detect.outputs.has_php == 'true'
        run: |
          if ! command -v php &> /dev/null; then
            sudo apt-get update -qq
            sudo apt-get install -y -qq php-cli php-mbstring php-xml >/dev/null 2>&1
          fi
          php -v

      - name: Setup Node.js
        if: steps.detect.outputs.has_node == 'true'
        uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Install PHP dependencies
        if: steps.detect.outputs.has_php == 'true'
        run: |
          if [ -f "composer.json" ]; then
            composer install --no-interaction --prefer-dist --quiet 2>/dev/null || true
          fi

      - name: Install Node.js dependencies
        if: steps.detect.outputs.has_node == 'true'
        run: |
          if [ -f "package.json" ]; then
            npm ci --quiet 2>/dev/null || npm install --quiet 2>/dev/null || true
          fi

      - name: PHP syntax check
        if: steps.detect.outputs.has_php == 'true'
        run: |
          ERRORS=0
          while IFS= read -r -d '' file; do
            if ! php -l "$file" 2>&1 | grep -q "No syntax errors"; then
              echo "::error file=${file}::PHP syntax error"
              ERRORS=$((ERRORS + 1))
            fi
          done < <(find . -name "*.php" -not -path "./.git/*" -not -path "./vendor/*" -not -path "./node_modules/*" -print0)

          echo "## PHP Lint" >> $GITHUB_STEP_SUMMARY
          if [ "$ERRORS" -eq 0 ]; then
            echo "All PHP files passed syntax check." >> $GITHUB_STEP_SUMMARY
          else
            echo "${ERRORS} file(s) with syntax errors." >> $GITHUB_STEP_SUMMARY
            exit 1
          fi

      - name: TypeScript/JavaScript lint
        if: steps.detect.outputs.has_node == 'true'
        run: |
          if [ -f "node_modules/.bin/eslint" ]; then
            npx eslint src/ --quiet 2>&1 || { echo "::error::ESLint errors found"; exit 1; }
            echo "## ESLint" >> $GITHUB_STEP_SUMMARY
            echo "All files passed ESLint." >> $GITHUB_STEP_SUMMARY
          elif [ -f ".eslintrc.json" ] || [ -f ".eslintrc.js" ] || [ -f "eslint.config.js" ]; then
            echo "::warning::ESLint config found but eslint not installed"
          else
            echo "No ESLint configured — skipping"
          fi

      - name: TypeScript compile check
        if: steps.detect.outputs.has_node == 'true'
        run: |
          if [ -f "tsconfig.json" ] && [ -f "node_modules/.bin/tsc" ]; then
            npx tsc --noEmit 2>&1 || { echo "::error::TypeScript compilation errors"; exit 1; }
            echo "## TypeScript" >> $GITHUB_STEP_SUMMARY
            echo "TypeScript compilation passed." >> $GITHUB_STEP_SUMMARY
          fi

      - name: PHPStan static analysis
        if: steps.detect.outputs.has_php == 'true'
        run: |
          if [ -f "phpstan.neon" ] && [ -f "vendor/bin/phpstan" ]; then
            vendor/bin/phpstan analyse --no-progress 2>&1 || { echo "::warning::PHPStan found issues"; }
          fi

  # ── Tests ─────────────────────────────────────────────────────────────
  test:
    name: Tests
    runs-on: ubuntu-latest
    needs: lint

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Detect toolchain
        id: detect
        run: |
          HAS_PHP=false
          HAS_NODE=false
          [ -f "composer.json" ] && HAS_PHP=true
          [ -f "package.json" ] && HAS_NODE=true
          echo "has_php=$HAS_PHP" >> "$GITHUB_OUTPUT"
          echo "has_node=$HAS_NODE" >> "$GITHUB_OUTPUT"

      - name: Setup PHP
        if: steps.detect.outputs.has_php == 'true'
        run: |
          if ! command -v php &> /dev/null; then
            sudo apt-get update -qq
            sudo apt-get install -y -qq php-cli php-mbstring php-xml >/dev/null 2>&1
          fi

      - name: Setup Node.js
        if: steps.detect.outputs.has_node == 'true'
        uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Install dependencies
        run: |
          [ -f "composer.json" ] && composer install --no-interaction --prefer-dist --quiet 2>/dev/null || true
          [ -f "package.json" ] && { npm ci --quiet 2>/dev/null || npm install --quiet 2>/dev/null || true; }

      - name: Run PHP tests
        if: steps.detect.outputs.has_php == 'true'
        run: |
          if [ -f "vendor/bin/phpunit" ]; then
            vendor/bin/phpunit --testdox 2>&1
            echo "## PHPUnit" >> $GITHUB_STEP_SUMMARY
            echo "Tests passed." >> $GITHUB_STEP_SUMMARY
          elif [ -f "phpunit.xml" ] || [ -f "phpunit.xml.dist" ]; then
            echo "::warning::PHPUnit config found but phpunit not installed"
          else
            echo "No PHPUnit configured — skipping"
          fi

      - name: Run Node.js tests
        if: steps.detect.outputs.has_node == 'true'
        run: |
          if jq -e '.scripts.test' package.json > /dev/null 2>&1; then
            npm test 2>&1
            echo "## Node.js Tests" >> $GITHUB_STEP_SUMMARY
            echo "Tests passed." >> $GITHUB_STEP_SUMMARY
          else
            echo "No test script in package.json — skipping"
          fi

      - name: Build check
        run: |
          if [ -f "Makefile" ]; then
            make build 2>&1 || echo "::warning::Build failed or not configured"
          elif [ -f "package.json" ] && jq -e '.scripts.build' package.json > /dev/null 2>&1; then
            npm run build 2>&1 || echo "::warning::Build failed"
          fi
