# =============================================================================
# GitLab CI/CD Pipeline — STEAM Security Dashboard
# =============================================================================
#
# Pipeline stages:
#   1. install   — install dependencies for backend and frontend
#   2. lint      — run linters / static checks
#   3. test      — run backend (Jest) and frontend (react-scripts) tests
#   4. build     — produce the production frontend bundle
#   5. deploy    — deploy to staging (local) or production (SSH to 71.85.90.6)
#   6. verify    — post-deploy health checks
#
# Environments:
#   staging    — dashboard-dev:3100 (auto-deploy on main/master)
#   production — 71.85.90.6:3001 (manual trigger, requires staging verification)
#
# Executor: shell (runs on dashboard-dev using system Node.js)
# =============================================================================

# ---------------------------------------------------------------------------
# Variables
# ---------------------------------------------------------------------------
variables:
  PROD_HOST: "71.85.90.6"
  PROD_USER: "root"
  PROD_DIR: "/home/cve-dashboard"
  STAGING_DIR: "/home/cve-dashboard-staging"

# ---------------------------------------------------------------------------
# Global cache — persists node_modules between pipeline runs
# ---------------------------------------------------------------------------
cache:
  key: ${CI_COMMIT_REF_SLUG}
  paths:
    - node_modules/
    - frontend/node_modules/
  policy: pull

# ---------------------------------------------------------------------------
# Stages
# ---------------------------------------------------------------------------
stages:
  - install
  - lint
  - test
  - build
  - deploy
  - verify

# =============================================================================
# STAGE 1: Install dependencies
# =============================================================================

install-backend:
  stage: install
  script:
    - npm ci --prefer-offline
  cache:
    key: ${CI_COMMIT_REF_SLUG}
    paths:
      - node_modules/
    policy: pull-push

install-frontend:
  stage: install
  script:
    - cd frontend && npm ci --prefer-offline
  cache:
    key: ${CI_COMMIT_REF_SLUG}
    paths:
      - frontend/node_modules/
    policy: pull-push

# =============================================================================
# STAGE 2: Lint / static analysis
# =============================================================================

lint-frontend:
  stage: lint
  script:
    - cd frontend && npm ci --prefer-offline && npx eslint src/ --ignore-pattern '**/__tests__/**' --ignore-pattern '**/*.test.js' --max-warnings 10
  needs:
    - install-frontend

lint-backend:
  stage: lint
  script:
    - npm ci --prefer-offline
    - node -c backend/server.js
    - node -c backend/routes/*.js
    - node -c backend/helpers/*.js
    - node -c backend/middleware/*.js
  needs:
    - install-backend

# =============================================================================
# STAGE 3: Tests
# =============================================================================

test-backend:
  stage: test
  script:
    - npm ci --prefer-offline
    - ./node_modules/.bin/jest --ci --forceExit backend/__tests__/
  timeout: 5 minutes
  needs:
    - install-backend

test-frontend:
  stage: test
  script:
    - npm ci --prefer-offline
    - cd frontend && npm ci --prefer-offline && CI=true npx react-scripts test --watchAll=false --ci
  timeout: 5 minutes
  needs:
    - install-frontend

# =============================================================================
# STAGE 4: Build
# =============================================================================

build-frontend:
  stage: build
  script:
    - cd frontend && npm ci --prefer-offline && CI=false REACT_APP_API_BASE=/api REACT_APP_API_HOST="" npm run build
  artifacts:
    paths:
      - frontend/build/
    expire_in: 7 days
  needs:
    - test-frontend
    - lint-frontend

# =============================================================================
# STAGE 5: Deploy
# =============================================================================

# ---------------------------------------------------------------------------
# Staging — auto-deploys on main/master to dashboard-dev:3100
# ---------------------------------------------------------------------------
deploy-staging:
  stage: deploy
  rules:
    - if: $CI_COMMIT_BRANCH == "main" || $CI_COMMIT_BRANCH == "master"
      when: on_success
  environment:
    name: staging
    url: http://localhost:3100
  script:
    - echo "Deploying to staging (dashboard-dev:3100)..."
    # Ensure staging directory exists
    - mkdir -p ${STAGING_DIR}
    # Sync code (exclude .git, node_modules, uploads, logs)
    - rsync -a --delete
        --exclude='.git'
        --exclude='node_modules'
        --exclude='frontend/node_modules'
        --exclude='frontend/build'
        --exclude='backend/uploads'
        --exclude='*.log'
        --exclude='*.db'
        --exclude='.env'
        ${CI_PROJECT_DIR}/ ${STAGING_DIR}/
    # Copy built frontend
    - cp -r ${CI_PROJECT_DIR}/frontend/build ${STAGING_DIR}/frontend/build
    # Install deps in staging
    - cd ${STAGING_DIR} && npm ci --prefer-offline
    - cd ${STAGING_DIR}/frontend && npm ci --prefer-offline
    # Ensure staging .env exists
    - |
      if [ ! -f "${STAGING_DIR}/backend/.env" ]; then
        cp ${CI_PROJECT_DIR}/backend/.env ${STAGING_DIR}/backend/.env
        sed -i 's/^PORT=.*/PORT=3100/' ${STAGING_DIR}/backend/.env
        grep -q "^PORT=" ${STAGING_DIR}/backend/.env || echo "PORT=3100" >> ${STAGING_DIR}/backend/.env
      fi
    # Run migrations
    - cd ${STAGING_DIR}/backend && node migrations/run-all.js
    # Restart staging service
    - sudo systemctl restart cve-backend-staging || sudo systemctl start cve-backend-staging || true
    - echo "Staging deploy complete."
  needs:
    - build-frontend
    - test-backend

# ---------------------------------------------------------------------------
# Production — manual trigger, SSH to 71.85.90.6
# ---------------------------------------------------------------------------
deploy-production:
  stage: deploy
  rules:
    - if: $CI_COMMIT_BRANCH == "main" || $CI_COMMIT_BRANCH == "master"
      when: manual
  environment:
    name: production
    url: http://71.85.90.6:3001
  script:
    - echo "Deploying to production (${PROD_HOST})..."
    # Record current commit on prod for rollback
    - ssh ${PROD_USER}@${PROD_HOST} "cd ${PROD_DIR} && git rev-parse HEAD 2>/dev/null || echo none" > /tmp/prod-prev-commit
    - echo "Previous production commit:$(cat /tmp/prod-prev-commit)"
    # Sync code to production (exclude local-only files)
    - rsync -az --delete
        --exclude='.git'
        --exclude='node_modules'
        --exclude='frontend/node_modules'
        --exclude='frontend/build'
        --exclude='backend/uploads'
        --exclude='*.log'
        --exclude='*.db'
        --exclude='.env'
        --exclude='.compliance-staging'
        ${CI_PROJECT_DIR}/ ${PROD_USER}@${PROD_HOST}:${PROD_DIR}/
    # Copy built frontend
    - rsync -az ${CI_PROJECT_DIR}/frontend/build/ ${PROD_USER}@${PROD_HOST}:${PROD_DIR}/frontend/build/
    # Install deps on production
    - ssh ${PROD_USER}@${PROD_HOST} "cd ${PROD_DIR} && npm ci --prefer-offline"
    - ssh ${PROD_USER}@${PROD_HOST} "cd ${PROD_DIR}/frontend && npm ci --prefer-offline"
    # Run migrations
    - ssh ${PROD_USER}@${PROD_HOST} "cd ${PROD_DIR}/backend && node migrations/run-all.js"
    # Restart services — install systemd unit if not present
    - ssh ${PROD_USER}@${PROD_HOST} "test -f /etc/systemd/system/cve-backend.service" || scp ${CI_PROJECT_DIR}/deploy/cve-backend-production.service ${PROD_USER}@${PROD_HOST}:/etc/systemd/system/cve-backend.service
    - ssh ${PROD_USER}@${PROD_HOST} "systemctl daemon-reload && systemctl enable cve-backend && systemctl restart cve-backend"
    - echo "Production deploy complete."
  needs:
    - build-frontend
    - test-backend

# =============================================================================
# STAGE 6: Post-deploy verification
# =============================================================================

# ---------------------------------------------------------------------------
# Staging health check
# ---------------------------------------------------------------------------
verify-staging:
  stage: verify
  rules:
    - if: $CI_COMMIT_BRANCH == "main" || $CI_COMMIT_BRANCH == "master"
      when: on_success
  script:
    - echo "Verifying staging..."
    - sleep 3
    - |
      for i in 1 2 3 4 5; do
        STATUS=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:3100/api/health 2>/dev/null || echo "000")
        if [ "$STATUS" = "200" ]; then
          echo "Staging health check passed (attempt $i)"
          break
        fi
        echo "Staging not ready (status: $STATUS), retrying... (attempt $i/5)"
        sleep 3
      done
      if [ "$STATUS" != "200" ]; then
        echo "FAILED: Staging health check failed after 5 attempts"
        exit 1
      fi
    - echo "Staging verification passed."
  needs:
    - deploy-staging

# ---------------------------------------------------------------------------
# Production health check — rolls back on failure
# ---------------------------------------------------------------------------
verify-production:
  stage: verify
  rules:
    - if: $CI_COMMIT_BRANCH == "main" || $CI_COMMIT_BRANCH == "master"
      when: on_success
  script:
    - echo "Verifying production..."
    - sleep 3
    - |
      for i in 1 2 3 4 5 6 7 8 9 10; do
        STATUS=$(curl -s -o /dev/null -w "%{http_code}" http://${PROD_HOST}:3001/api/health 2>/dev/null || echo "000")
        if [ "$STATUS" = "200" ]; then
          echo "Production health check passed (attempt $i)"
          break
        fi
        echo "Production not ready (status: $STATUS), retrying... (attempt $i/10)"
        sleep 3
      done
      if [ "$STATUS" != "200" ]; then
        echo "FAILED: Production health check failed — initiating rollback"
        PREV_COMMIT=$(cat /tmp/prod-prev-commit 2>/dev/null || echo "")
        if [ -n "$PREV_COMMIT" ] && [ "$PREV_COMMIT" != "none" ]; then
          echo "Rolling back to $PREV_COMMIT..."
          # Re-sync the previous version
          ssh ${PROD_USER}@${PROD_HOST} "cd ${PROD_DIR} && git checkout ${PREV_COMMIT} --force 2>/dev/null" || true
          ssh ${PROD_USER}@${PROD_HOST} "cd ${PROD_DIR} && npm ci --prefer-offline"
          ssh ${PROD_USER}@${PROD_HOST} "systemctl restart cve-backend"
          echo "Rollback complete. Verify manually."
        else
          echo "No previous commit recorded — manual intervention required."
        fi
        exit 1
      fi
    - echo "Production verification passed."
  needs:
    - deploy-production
  allow_failure: false
