# =============================================================================
# AWOOOI CI Pipeline v2.0 (沿用 AIOPS 最佳實踐)
# =============================================================================

name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
  workflow_dispatch:

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

env:
  NODE_VERSION: '20'
  PNPM_VERSION: '9'
  PYTHON_VERSION: '3.11'
  # OTEL CI/CD 監控 (2026-03-24 批准, 2026-03-28 修正: SignOz 在 188)
  OTEL_EXPORTER_OTLP_ENDPOINT: http://192.168.0.188:24318
  OTEL_SERVICE_NAME: awoooi-ci
  OTEL_RESOURCE_ATTRIBUTES: service.version=${{ github.sha }},deployment.environment=ci

jobs:
  # ==================== Pre-flight (10s Fail-Fast) ====================
  pre-flight:
    name: "Pre-flight"
    runs-on: [self-hosted, harbor, k8s]
    timeout-minutes: 1
    steps:
      # 2026-03-29 Claude Code: 修復 _diag/pages 檔案衝突
      - name: "Clean Runner Diagnostics"
        run: |
          RUNNER_ROOT=$(dirname "$(dirname "$RUNNER_TEMP")")
          rm -rf "$RUNNER_ROOT/_diag/pages" 2>/dev/null || true
          mkdir -p "$RUNNER_ROOT/_diag/pages" 2>/dev/null || true

      - name: Quick sanity check
        run: |
          echo "✅ Runner 可用"
          node --version || echo "⚠️ Node not found"
          python3 --version || echo "⚠️ Python not found"

  # ==================== Lint & Type Check ====================
  lint:
    name: Lint & Type Check
    runs-on: [self-hosted, harbor, k8s]
    needs: pre-flight
    timeout-minutes: 10
    steps:
      # 2026-03-29 Claude Code: 修復 _diag/pages 檔案衝突
      - name: "Clean Runner Diagnostics"
        run: |
          RUNNER_ROOT=$(dirname "$(dirname "$RUNNER_TEMP")")
          rm -rf "$RUNNER_ROOT/_diag/pages" 2>/dev/null || true
          mkdir -p "$RUNNER_ROOT/_diag/pages" 2>/dev/null || true

      - uses: actions/checkout@v4
        with:
          clean: true

      # 清理 worktrees (在 checkout 後，確保在 workspace 內)
      - name: Clean worktrees
        run: rm -rf ${{ github.workspace }}/.claude/worktrees 2>/dev/null || true

      - name: Setup pnpm
        uses: pnpm/action-setup@v3
        with:
          version: ${{ env.PNPM_VERSION }}

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: 'pnpm'

      - name: Install dependencies
        run: pnpm install --frozen-lockfile

      - name: Lint
        run: pnpm lint

      - name: Type check
        run: pnpm typecheck

      # Phase 14.2: 依賴治理 (2026-03-26)
      - name: Dependency Check
        run: pnpm dep-check

      - name: ADR Compliance Check
        run: |
          echo "🔍 檢查 ADR 規定..."
          # 檢查 1: 前端禁止直連資料庫 (ADR-005)
          if grep -rE "psycopg2|asyncpg|redis|sqlalchemy|pg|ioredis" apps/web/src/ 2>/dev/null; then
            echo "❌ ADR-005 違規: 前端禁止直連資料庫"
            exit 1
          fi
          # 檢查 2: 禁止 Redux (ADR-004)
          if grep -rE "@reduxjs/toolkit|react-redux" apps/web/package.json 2>/dev/null; then
            echo "❌ ADR-004 違規: 禁止 Redux"
            exit 1
          fi
          # 檢查 3: 禁止 import 舊專案
          if grep -rE "from ['\"].*wooo-aiops" apps/ packages/ 2>/dev/null; then
            echo "❌ 禁止 import 舊專案"
            exit 1
          fi
          echo "✅ ADR 檢查通過"

      # Phase 14.2 #96: 後端分層檢查 (輕量版 import-linter)
      - name: API Layer Check
        run: |
          echo "🔍 檢查後端分層規則..."
          # 檢查 1: services 層禁止引用 api/routers 層 (反向依賴)
          if grep -rE "from src\.(api|routers)" apps/api/src/services/ 2>/dev/null; then
            echo "❌ 分層違規: services 禁止引用 api/routers 層"
            exit 1
          fi
          # 檢查 2: repositories 層禁止引用 services 層
          if grep -rE "from src\.services" apps/api/src/repositories/ 2>/dev/null; then
            echo "❌ 分層違規: repositories 禁止引用 services 層"
            exit 1
          fi
          # 檢查 3: models 層禁止引用業務層
          if grep -rE "from src\.(services|api|routers)" apps/api/src/models/ 2>/dev/null; then
            echo "❌ 分層違規: models 禁止引用業務層"
            exit 1
          fi
          echo "✅ 後端分層檢查通過"

  # ==================== Test ====================
  test:
    name: Test
    runs-on: [self-hosted, harbor, k8s]
    needs: lint
    timeout-minutes: 15
    steps:
      - name: "Clean Runner Diagnostics"
        run: |
          RUNNER_ROOT=$(dirname "$(dirname "$RUNNER_TEMP")")
          rm -rf "$RUNNER_ROOT/_diag/pages" 2>/dev/null || true
          mkdir -p "$RUNNER_ROOT/_diag/pages" 2>/dev/null || true
      - uses: actions/checkout@v4

      - name: Setup pnpm
        uses: pnpm/action-setup@v3
        with:
          version: ${{ env.PNPM_VERSION }}

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: 'pnpm'

      - name: Install dependencies
        run: pnpm install --frozen-lockfile

      - name: Run tests
        run: pnpm test
        continue-on-error: true

      - name: Upload coverage
        uses: codecov/codecov-action@v4
        with:
          token: ${{ secrets.CODECOV_TOKEN }}
          fail_ci_if_error: false

  # ==================== Build ====================
  build:
    name: Build
    runs-on: [self-hosted, harbor, k8s]
    needs: lint
    timeout-minutes: 15
    steps:
      - name: "Clean Runner Diagnostics"
        run: |
          RUNNER_ROOT=$(dirname "$(dirname "$RUNNER_TEMP")")
          rm -rf "$RUNNER_ROOT/_diag/pages" 2>/dev/null || true
          mkdir -p "$RUNNER_ROOT/_diag/pages" 2>/dev/null || true
      - uses: actions/checkout@v4

      - name: Setup pnpm
        uses: pnpm/action-setup@v3
        with:
          version: ${{ env.PNPM_VERSION }}

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: 'pnpm'

      - name: Install dependencies
        run: pnpm install --frozen-lockfile

      - name: Setup Turborepo Cache
        uses: dtinth/setup-github-actions-caching-for-turbo@v1

      - name: Build packages
        env:
          NEXT_PUBLIC_API_URL: https://awoooi.wooo.work
          # Sentry DSN (透過 /api/sentry-tunnel 避免區域網路權限問題)
          NEXT_PUBLIC_SENTRY_DSN: http://da02d4e5d6542e4d1ed6b2dd6542efeb@192.168.0.110:9000/2
        run: pnpm turbo build

      - name: Upload build artifacts
        uses: actions/upload-artifact@v4
        with:
          name: build-artifacts
          path: |
            apps/*/dist
            packages/*/dist
          retention-days: 7

  # ==================== API Lint (Python) ====================
  api-lint:
    name: API Lint
    runs-on: [self-hosted, harbor, k8s]
    needs: pre-flight
    timeout-minutes: 5
    steps:
      - name: "Clean Runner Diagnostics"
        run: |
          RUNNER_ROOT=$(dirname "$(dirname "$RUNNER_TEMP")")
          rm -rf "$RUNNER_ROOT/_diag/pages" 2>/dev/null || true
          mkdir -p "$RUNNER_ROOT/_diag/pages" 2>/dev/null || true
      - uses: actions/checkout@v4

      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: ${{ env.PYTHON_VERSION }}

      - name: Install uv
        uses: astral-sh/setup-uv@v3

      - name: Install & Lint
        working-directory: apps/api
        run: |
          uv sync
          uv run ruff check .

      - name: Type check
        working-directory: apps/api
        run: uv run mypy src/ --exclude 'tests/|scripts/' || true
        continue-on-error: true

  # ==================== API Test ====================
  api-test:
    name: API Test
    runs-on: [self-hosted, harbor, k8s]
    needs: api-lint
    timeout-minutes: 10
    steps:
      - name: "Clean Runner Diagnostics"
        run: |
          RUNNER_ROOT=$(dirname "$(dirname "$RUNNER_TEMP")")
          rm -rf "$RUNNER_ROOT/_diag/pages" 2>/dev/null || true
          mkdir -p "$RUNNER_ROOT/_diag/pages" 2>/dev/null || true
      - uses: actions/checkout@v4

      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: ${{ env.PYTHON_VERSION }}

      - name: Install uv
        uses: astral-sh/setup-uv@v3

      - name: Install & Test
        working-directory: apps/api
        env:
          PYTHONPATH: ${{ github.workspace }}/apps/api
        run: |
          uv sync
          uv run pytest tests/ --cov=src --cov-report=xml -v || true
        continue-on-error: true

  # ==================== Ollama Model Test (Phase 12.3 #67) ====================
  # 🤖 自動化模型回歸測試 - 確保 OpenClaw 提案品質
  ollama-test:
    name: Ollama Model Test
    runs-on: [self-hosted, harbor, k8s]
    needs: api-lint
    timeout-minutes: 5
    continue-on-error: true  # 不阻塞主 Pipeline
    steps:
      - name: "Clean Runner Diagnostics"
        run: |
          RUNNER_ROOT=$(dirname "$(dirname "$RUNNER_TEMP")")
          rm -rf "$RUNNER_ROOT/_diag/pages" 2>/dev/null || true
          mkdir -p "$RUNNER_ROOT/_diag/pages" 2>/dev/null || true
      - uses: actions/checkout@v4

      - name: Test Ollama Connectivity
        run: |
          echo "🔗 測試 Ollama 連線..."
          if curl -s --connect-timeout 5 http://192.168.0.188:11434/api/tags > /dev/null; then
            echo "✅ Ollama 可達"
            # 使用 Python 替代 jq (Runner 未安裝 jq)
            curl -s http://192.168.0.188:11434/api/tags | python3 -c "import sys,json; [print(m['name']) for m in json.load(sys.stdin).get('models',[])]"
          else
            echo "⚠️ Ollama 無法連線 (192.168.0.188:11434)"
            exit 0  # 不失敗，只警告
          fi

      - name: Model Smoke Test
        run: |
          echo "🧪 模型冒煙測試..."
          # 使用 Python 替代 jq
          RESPONSE=$(curl -s --max-time 60 http://192.168.0.188:11434/api/generate -d '{
            "model": "qwen2.5:7b-instruct",
            "prompt": "你是 AIOps 助手。回答：1+1=?",
            "stream": false
          }' | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('response','ERROR'))" 2>/dev/null || echo "ERROR")

          if [ "$RESPONSE" != "ERROR" ] && [ -n "$RESPONSE" ]; then
            echo "✅ 模型回應正常"
            echo "回應: $RESPONSE"
          else
            echo "⚠️ 模型回應異常"
          fi

      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: ${{ env.PYTHON_VERSION }}

      - name: Install uv
        uses: astral-sh/setup-uv@v3

      - name: Action Parsing Test
        working-directory: apps/api
        env:
          PYTHONPATH: ${{ github.workspace }}/apps/api
        run: |
          echo "🔍 Action Parsing 回歸測試..."
          uv sync
          uv run pytest tests/test_action_parsing.py -v --tb=short || echo "⚠️ 部分測試失敗"

      # 🔴 LLM 測試移至 Nightly (2026-03-26)
      # 原因: CPU 推理需 300+ 秒/測試，不適合每次 commit
      # 完整測試: .github/workflows/nightly-llm.yaml
      - name: LLM Test (Skip - See Nightly)
        run: |
          echo "⏭️ LLM 測試已移至 Nightly workflow"
          echo "   - test_model_regression.py"
          echo "   - test_prompt_validation.py"
          echo "   原因: CPU 推理 ~300s/測試"

  # ==================== OpenAPI Validation ====================
  openapi-validate:
    name: OpenAPI Validate
    runs-on: [self-hosted, harbor, k8s]
    needs: pre-flight
    timeout-minutes: 3
    steps:
      - name: "Clean Runner Diagnostics"
        run: |
          RUNNER_ROOT=$(dirname "$(dirname "$RUNNER_TEMP")")
          rm -rf "$RUNNER_ROOT/_diag/pages" 2>/dev/null || true
          mkdir -p "$RUNNER_ROOT/_diag/pages" 2>/dev/null || true
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}

      - name: Validate
        run: |
          # 修復 ENOTEMPTY npm 錯誤 - 先清理舊目錄
          rm -rf $(npm root -g)/@stoplight/spectral-cli 2>/dev/null || true
          npm install -g @stoplight/spectral-cli || npm install -g @stoplight/spectral-cli
          spectral lint docs/api/api-contract.yaml || true

  # ==================== Docker Build Verify ====================
  # 🚀 優化 (2026-03-24): 只在 PR 時執行，main push 跳過 (CD 會構建)
  docker-build:
    name: Docker Verify
    runs-on: [self-hosted, harbor, k8s]
    needs: [test, api-test, build]
    if: github.event_name == 'pull_request'
    timeout-minutes: 20
    strategy:
      matrix:
        app: [web, api]
    steps:
      - name: "Clean Runner Diagnostics"
        run: |
          RUNNER_ROOT=$(dirname "$(dirname "$RUNNER_TEMP")")
          rm -rf "$RUNNER_ROOT/_diag/pages" 2>/dev/null || true
          mkdir -p "$RUNNER_ROOT/_diag/pages" 2>/dev/null || true
      - uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Build (no push)
        uses: docker/build-push-action@v5
        with:
          context: .
          file: apps/${{ matrix.app }}/Dockerfile
          push: false
          tags: awoooi-${{ matrix.app }}:test
          build-args: |
            NEXT_PUBLIC_API_URL=https://awoooi.wooo.work
            NEXT_PUBLIC_SENTRY_DSN=http://da02d4e5d6542e4d1ed6b2dd6542efeb@192.168.0.110:9000/2
          cache-from: type=gha
          cache-to: type=gha,mode=max
