# ============================================================
# OmniCommerce Cloud — CI/CD Pipeline
# GitHub Actions — Build, Test, Scan, Deploy
# ============================================================

name: OmniCommerce CI/CD Pipeline

on:
  push:
    branches: [main, develop]
    paths-ignore:
      - 'docs/**'
      - '*.md'
      - '.gitignore'
  pull_request:
    branches: [main]
    types: [opened, synchronize, reopened, ready_for_review]
  release:
    types: [published]
  workflow_dispatch:
    inputs:
      environment:
        description: 'Deploy to environment'
        required: true
        default: 'staging'
        type: choice
        options: [staging, production]
      service:
        description: 'Service to deploy (empty = all)'
        required: false
        type: string

env:
  REGISTRY: ghcr.io
  REGISTRY_USER: ${{ github.actor }}
  IMAGE_PREFIX: omnicommerce
  DOCKER_BUILDKIT: 1
  COMPOSE_DOCKER_CLI_BUILD: 1

# ============================================================
# CONCURRENCY CONTROL
# ============================================================
concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event.inputs.environment || 'default' }}
  cancel-in-progress: true

jobs:
  # ==================== DETECT CHANGES ====================
  detect-changes:
    name: 🔍 Detect Changes
    runs-on: ubuntu-latest
    outputs:
      backend: ${{ steps.filter.outputs.backend }}
      web: ${{ steps.filter.outputs.web }}
      admin: ${{ steps.filter.outputs.admin }}
      vendor: ${{ steps.filter.outputs.vendor }}
      mobile: ${{ steps.filter.outputs.mobile }}
      infra: ${{ steps.filter.outputs.infra }}
      database: ${{ steps.filter.outputs.database }}
    steps:
      - uses: actions/checkout@v4
      - uses: dorny/paths-filter@v3
        id: filter
        with:
          filters: |
            backend:
              - 'backend/**'
              - 'go.mod'
              - 'go.sum'
            web:
              - 'frontend/web/**'
            admin:
              - 'frontend/admin/**'
            vendor:
              - 'frontend/vendor-dashboard/**'
            mobile:
              - 'mobile/**'
            infra:
              - 'infrastructure/**'
              - '.github/workflows/**'
            database:
              - 'database/**'

  # ==================== SETUP ====================
  setup:
    name: ⚙️ Setup
    runs-on: ubuntu-latest
    needs: detect-changes
    outputs:
      short_sha: ${{ steps.vars.outputs.short_sha }}
      version: ${{ steps.vars.outputs.version }}
    steps:
      - uses: actions/checkout@v4
      - id: vars
        run: |
          echo "short_sha=$(git rev-parse --short=8 HEAD)" >> $GITHUB_OUTPUT
          echo "version=$(git describe --tags --always --dirty 2>/dev/null || echo 'dev')" >> $GITHUB_OUTPUT

  # ==================== LINT & FORMAT ====================
  lint:
    name: 📝 Lint & Format Check
    runs-on: ubuntu-latest
    needs: setup
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-go@v5
        with:
          go-version: '1.22'
          cache: true
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
      - name: Go Lint
        if: needs.detect-changes.outputs.backend == 'true'
        working-directory: backend
        run: |
          go vet ./...
          go install golang.org/x/lint/golint@latest
          golint ./...
      - name: Frontend Lint
        if: needs.detect-changes.outputs.web == 'true' || needs.detect-changes.outputs.admin == 'true'
        run: |
          npm ci
          npx prettier --check "frontend/**/*.{ts,tsx,json}"
          npx eslint "frontend/**/*.{ts,tsx}"

  # ==================== TESTS ====================
  test:
    name: 🧪 Tests
    runs-on: ubuntu-latest
    needs: [setup, lint]
    strategy:
      fail-fast: false
      matrix:
        service: [backend, web, admin, vendor]
    services:
      postgres:
        image: postgres:16-alpine
        env:
          POSTGRES_DB: omnicommerce_test
          POSTGRES_USER: test
          POSTGRES_PASSWORD: test
        ports:
          - 5432:5432
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
      redis:
        image: redis:7-alpine
        ports:
          - 6379:6379
    steps:
      - uses: actions/checkout@v4
      - name: Go Tests
        if: matrix.service == 'backend' && needs.detect-changes.outputs.backend == 'true'
        uses: actions/setup-go@v5
        with:
          go-version: '1.22'
      - if: matrix.service == 'backend' && needs.detect-changes.outputs.backend == 'true'
        working-directory: backend
        run: |
          go test -v -race -coverprofile=coverage.out -covermode=atomic ./...
          go tool cover -func=coverage.out
      - name: Frontend Tests
        if: matrix.service != 'backend' && needs.detect-changes.outputs[matrix.service] == 'true'
        uses: actions/setup-node@v4
        with:
          node-version: '20'
      - if: matrix.service != 'backend' && needs.detect-changes.outputs[matrix.service] == 'true'
        working-directory: frontend/${{ matrix.service }}
        run: |
          npm ci
          npm run test -- --coverage --passWithNoTests

  # ==================== SECURITY SCAN ====================
  security-scan:
    name: 🔒 Security Scan
    runs-on: ubuntu-latest
    needs: [setup, detect-changes]
    steps:
      - uses: actions/checkout@v4
      
      # Trivy — Container Image Scanner
      - name: Trivy Scan (Dockerfiles)
        uses: aquasecurity/trivy-action@master
        with:
          scan-type: 'config'
          scan-ref: '.'
          format: 'sarif'
          output: 'trivy-results.sarif'
          severity: 'CRITICAL,HIGH'
      
      # Go Vulnerability Check
      - name: Go Vulnerability Check
        if: needs.detect-changes.outputs.backend == 'true'
        working-directory: backend
        run: |
          go install golang.org/x/vuln/cmd/govulncheck@latest
          govulncheck ./...
      
      # Detect Secrets
      - name: Detect Secrets
        uses: gitleaks/gitleaks-action@v2
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      # npm audit
      - name: npm Audit
        if: needs.detect-changes.outputs.web == 'true' || needs.detect-changes.outputs.admin == 'true'
        run: |
          npm audit --production --audit-level=high || true

  # ==================== BUILD & PUSH ====================
  build:
    name: 🏗️ Build & Push
    runs-on: ubuntu-latest
    needs: [test, security-scan, setup]
    if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop' || github.event_name == 'release'
    strategy:
      fail-fast: false
      matrix:
        include:
          - service: backend
            context: backend
            dockerfile: backend/Dockerfile
            condition: backend
          - service: web
            context: frontend/web
            dockerfile: frontend/web/Dockerfile
            condition: web
          - service: admin
            context: frontend/admin
            dockerfile: frontend/admin/Dockerfile
            condition: admin
          - service: vendor
            context: frontend/vendor-dashboard
            dockerfile: frontend/vendor-dashboard/Dockerfile
            condition: vendor
    steps:
      - uses: actions/checkout@v4
      
      - name: Set up QEMU
        uses: docker/setup-qemu-action@v3
      
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3
        with:
          driver-opts: |
            image=moby/buildkit:latest
            network=host
      
      - name: Login to Container Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ env.REGISTRY_USER }}
          password: ${{ secrets.GITHUB_TOKEN }}
      
      - name: Docker Meta
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ github.repository_owner }}/${{ env.IMAGE_PREFIX }}-${{ matrix.service }}
          tags: |
            type=ref,event=branch
            type=ref,event=pr
            type=semver,pattern={{version}}
            type=semver,pattern={{major}}.{{minor}}
            type=sha,prefix=,format=short
            type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
            type=raw,value=${{ needs.setup.outputs.version }}
      
      - name: Build and Push
        uses: docker/build-push-action@v5
        with:
          context: ${{ matrix.context }}
          file: ${{ matrix.dockerfile }}
          push: ${{ github.event_name != 'pull_request' }}
          platforms: linux/amd64,linux/arm64
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha,scope=${{ matrix.service }}
          cache-to: type=gha,mode=max,scope=${{ matrix.service }}
          build-args: |
            APP_VERSION=${{ needs.setup.outputs.version }}
            BUILD_DATE=${{ github.event.head_commit.timestamp }}
            VCS_REF=${{ github.sha }}

  # ==================== DEPLOY ====================
  deploy:
    name: 🚀 Deploy
    runs-on: ubuntu-latest
    needs: [build, setup]
    if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop' || github.event_name == 'release'
    environment:
      name: ${{ github.ref == 'refs/heads/main' && 'production' || 'staging' }}
      url: https://${{ github.ref == 'refs/heads/main' && 'omnicommerce.io' || 'staging.omnicommerce.io' }}
    steps:
      - uses: actions/checkout@v4

      # ============ AWS DEPLOY ============
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ${{ secrets.AWS_REGION || 'us-east-1' }}

      - name: Login to Amazon ECR
        uses: aws-actions/amazon-ecr-login@v2

      - name: Update kubeconfig
        run: |
          aws eks update-kubeconfig \
            --name omnicommerce-${{ github.ref == 'refs/heads/main' && 'prod' || 'staging' }} \
            --region ${{ secrets.AWS_REGION || 'us-east-1' }}

      # ============ SET IMAGE TAGS ============
      - name: Update Image Tags
        run: |
          SHORT_SHA=${{ needs.setup.outputs.short_sha }}
          ENV_DIR=${{ github.ref == 'refs/heads/main' && 'production' || 'staging' }}
          
          cd infrastructure/kubernetes/overlays/$ENV_DIR
          
          kustomize edit set image \
            registry.omnicommerce.io/omnicommerce-api=ghcr.io/${{ github.repository_owner }}/omnicommerce-backend:${SHORT_SHA} \
            registry.omnicommerce.io/omnicommerce-web=ghcr.io/${{ github.repository_owner }}/omnicommerce-web:${SHORT_SHA} \
            registry.omnicommerce.io/omnicommerce-admin=ghcr.io/${{ github.repository_owner }}/omnicommerce-admin:${SHORT_SHA} \
            registry.omnicommerce.io/omnicommerce-vendor=ghcr.io/${{ github.repository_owner }}/omnicommerce-vendor:${SHORT_SHA}

      # ============ KUBERNETES DEPLOY ============
      - name: Deploy to Kubernetes
        run: |
          ENV_DIR=${{ github.ref == 'refs/heads/main' && 'production' || 'staging' }}
          kubectl apply -k infrastructure/kubernetes/overlays/$ENV_DIR --prune -l app.kubernetes.io/part-of=omnicommerce

      # ============ VERIFY DEPLOYMENT ============
      - name: Verify Deployments
        run: |
          for svc in backend web admin vendor-dashboard; do
            echo "Checking $svc..."
            kubectl rollout status deployment/$svc -n omnicommerce --timeout=300s
          done

      # ============ HEALTH CHECK ============
      - name: API Health Check
        run: |
          RETRIES=12
          INTERVAL=5
          for i in $(seq 1 $RETRIES); do
            STATUS=$(curl -s -o /dev/null -w "%{http_code}" https://api.${{ github.ref == 'refs/heads/main' && 'omnicommerce.io' || 'staging.omnicommerce.io' }}/health)
            if [ "$STATUS" == "200" ]; then
              echo "✅ API is healthy"
              exit 0
            fi
            echo "⏳ Waiting... ($i/$RETRIES)"
            sleep $INTERVAL
          done
          echo "❌ API health check failed after $RETRIES retries"
          exit 1

      # ============ ROLLBACK ON FAILURE ============
      - name: Rollback on Failure
        if: failure()
        run: |
          echo "🚨 Deployment failed! Rolling back..."
          ENV_DIR=${{ github.ref == 'refs/heads/main' && 'production' || 'staging' }}
          kubectl rollout undo deployment/backend -n omnicommerce
          kubectl rollout undo deployment/web -n omnicommerce
          kubectl rollout undo deployment/admin -n omnicommerce
          kubectl rollout undo deployment/vendor-dashboard -n omnicommerce

      # ============ NOTIFY ============
      - name: Notify Success
        if: success()
        uses: slackapi/slack-github-action@v1.26
        with:
          channel-id: ${{ secrets.SLACK_DEPLOY_CHANNEL }}
          slack-message: |
            ✅ *Deployment Successful*
            • Environment: ${{ github.ref == 'refs/heads/main' && 'Production' || 'Staging' }}
            • Version: `${{ needs.setup.outputs.version }}`
            • SHA: `${{ needs.setup.outputs.short_sha }}`
            • Trigger: ${{ github.event_name }}
            • By: ${{ github.actor }}
            • URL: https://${{ github.ref == 'refs/heads/main' && 'omnicommerce.io' || 'staging.omnicommerce.io' }}

      - name: Notify Failure
        if: failure()
        uses: slackapi/slack-github-action@v1.26
        with:
          channel-id: ${{ secrets.SLACK_ALERT_CHANNEL }}
          slack-message: |
            🚨 *Deployment Failed*
            • Environment: ${{ github.ref == 'refs/heads/main' && 'Production' || 'Staging' }}
            • Version: `${{ needs.setup.outputs.version }}`
            • SHA: `${{ needs.setup.outputs.short_sha }}`
            • Trigger: ${{ github.event_name }}
            • By: ${{ github.actor }}
            • Run: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}

  # ==================== DATABASE MIGRATIONS ====================
  migrate:
    name: 🗄️ Database Migrations
    runs-on: ubuntu-latest
    needs: [build, setup]
    if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop'
    environment:
      name: ${{ github.ref == 'refs/heads/main' && 'production' || 'staging' }}
    steps:
      - uses: actions/checkout@v4
      - name: Run Migrations
        run: |
          # Using golang-migrate or flyway
          docker run --rm \
            -v $(pwd)/database/migrations:/migrations \
            migrate/migrate \
            -path=/migrations \
            -database="${{ secrets.DATABASE_URL }}" \
            up

  # ==================== E2E TESTS ====================
  e2e:
    name: 🎭 E2E Tests
    runs-on: ubuntu-latest
    needs: deploy
    if: github.ref == 'refs/heads/main'
    timeout-minutes: 30
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      
      - name: Install Playwright
        run: |
          npm ci
          npx playwright install --with-deps chromium
      
      - name: Run E2E Tests
        env:
          BASE_URL: https://omnicommerce.io
          TEST_USER_EMAIL: ${{ secrets.E2E_USER_EMAIL }}
          TEST_USER_PASSWORD: ${{ secrets.E2E_USER_PASSWORD }}
        run: |
          npx playwright test --project=chromium --reporter=html,github
      
      - name: Upload Test Results
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: playwright-report
          path: playwright-report/

  # ==================== PERFORMANCE TESTING ====================
  performance:
    name: ⚡ Performance Test
    runs-on: ubuntu-latest
    needs: deploy
    if: github.event_name == 'release'
    steps:
      - uses: actions/checkout@v4
      
      - name: Run k6 Load Tests
        uses: grafana/k6-action@v0.3.1
        with:
          filename: infrastructure/tests/k6/load-test.js
          flags: --out json=results.json
        env:
          BASE_URL: https://api.omnicommerce.io
      
      - name: Check Performance Thresholds
        run: |
          # Parse k6 results and validate thresholds
          python3 -c "
          import json
          with open('results.json') as f:
              data = json.load(f)
          # Check p95 < 500ms
          metrics = data.get('metrics', {})
          p95 = metrics.get('http_req_duration', {}).get('values', {}).get('p(95)', 0)
          print(f'p95 latency: {p95}ms')
          if p95 > 500:
              raise Exception(f'p95 latency {p95}ms exceeds 500ms threshold')
          "

  # ==================== NOTIFICATIONS (Final) ====================
  release-notify:
    name: 📢 Release Notification
    runs-on: ubuntu-latest
    needs: [deploy, e2e]
    if: github.event_name == 'release'
    steps:
      - name: Create Sentry Release
        uses: getsentry/action-release@v1
        env:
          SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
          SENTRY_ORG: omnicommerce
          SENTRY_PROJECT: omnicommerce-api
        with:
          environment: production
          version: ${{ needs.setup.outputs.version }}
      
      - name: Notify PagerDuty
        if: failure()
        uses: PagerDuty/pagerduty-change-event-action@v1
        with:
          token: ${{ secrets.PAGERDUTY_TOKEN }}
          summary: "OmniCommerce ${{ needs.setup.outputs.version }} released"
          source: "CI/CD Pipeline"
          links: "[{\"href\": \"${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\", \"text\": \"View Pipeline\"}]"
