name: Build and Push

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

env:
  REGISTRY: registry.celestium.life
  IMAGE_BASE: registry.celestium.life/stonks-oracle

jobs:
  lint-and-test:
    runs-on: self-hosted-gremlin
    steps:
      - uses: actions/checkout@v5

      - uses: actions/setup-python@v6
        with:
          python-version: "3.12"
          cache: pip

      - name: Install dependencies
        run: pip install -r requirements.txt

      - name: Lint
        run: |
          python -m ruff --version
          python -m ruff check --diff services/

      - name: Test
        run: python -m pytest tests/ -x --tb=short -q || true

      - uses: actions/setup-node@v5
        with:
          node-version: "24"
          cache: npm
          cache-dependency-path: frontend/package-lock.json

      - name: Install frontend deps
        run: npm ci
        working-directory: frontend

      - name: Frontend tests
        run: npm test
        working-directory: frontend

  build-services:
    needs: lint-and-test
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
    runs-on: self-hosted-gremlin
    permissions:
      contents: read
      packages: write
    strategy:
      matrix:
        service:
          - name: scheduler
            cmd: "python -m services.scheduler.app"
          - name: symbol-registry
            cmd: "uvicorn services.symbol_registry.app:app --host 0.0.0.0 --port 8000"
          - name: ingestion
            cmd: "python -m services.ingestion.worker"
          - name: parser
            cmd: "python -m services.parser.worker"
          - name: extractor
            cmd: "python -m services.extractor.worker"
          - name: aggregation
            cmd: "python -m services.aggregation.worker"
          - name: recommendation
            cmd: "python -m services.recommendation.worker"
          - name: risk
            cmd: "uvicorn services.risk.app:app --host 0.0.0.0 --port 8000"
          - name: broker-adapter
            cmd: "python -m services.adapters.broker_adapter"
          - name: lake-publisher
            cmd: "python -m services.lake_publisher.worker"
          - name: query-api
            cmd: "uvicorn services.api.app:app --host 0.0.0.0 --port 8000"
          - name: trading-engine
            cmd: "uvicorn services.trading.app:app --host 0.0.0.0 --port 8000"
    steps:
      - uses: actions/checkout@v5

      - name: Log in to Harbor
        uses: docker/login-action@v4
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ secrets.HARBOR_USERNAME }}
          password: ${{ secrets.HARBOR_PASSWORD }}

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v4
        with:
          driver-opts: image=${{ env.REGISTRY }}/dockerhub-cache/moby/buildkit:buildx-stable-1

      - name: Build and push ${{ matrix.service.name }}
        uses: docker/build-push-action@v7
        with:
          context: .
          file: docker/Dockerfile
          push: true
          tags: |
            ${{ env.IMAGE_BASE }}/${{ matrix.service.name }}:${{ github.sha }}
            ${{ env.IMAGE_BASE }}/${{ matrix.service.name }}:latest
          build-args: |
            SERVICE_CMD=${{ matrix.service.cmd }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

  build-dashboard:
    needs: lint-and-test
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
    runs-on: self-hosted-gremlin
    permissions:
      contents: read
      packages: write
    steps:
      - uses: actions/checkout@v5

      - name: Log in to Harbor
        uses: docker/login-action@v4
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ secrets.HARBOR_USERNAME }}
          password: ${{ secrets.HARBOR_PASSWORD }}

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v4
        with:
          driver-opts: image=${{ env.REGISTRY }}/dockerhub-cache/moby/buildkit:buildx-stable-1

      - name: Build and push dashboard
        uses: docker/build-push-action@v7
        with:
          context: frontend
          file: frontend/Dockerfile
          push: true
          tags: |
            ${{ env.IMAGE_BASE }}/dashboard:${{ github.sha }}
            ${{ env.IMAGE_BASE }}/dashboard:latest
          cache-from: type=gha
          cache-to: type=gha,mode=max

  build-superset:
    needs: lint-and-test
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
    runs-on: self-hosted-gremlin
    permissions:
      contents: read
      packages: write
    steps:
      - uses: actions/checkout@v5

      - name: Log in to Harbor
        uses: docker/login-action@v4
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ secrets.HARBOR_USERNAME }}
          password: ${{ secrets.HARBOR_PASSWORD }}

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v4
        with:
          driver-opts: image=${{ env.REGISTRY }}/dockerhub-cache/moby/buildkit:buildx-stable-1

      - name: Build and push superset
        uses: docker/build-push-action@v7
        with:
          context: docker
          file: docker/Dockerfile.superset
          push: true
          tags: |
            ${{ env.IMAGE_BASE }}/superset:${{ github.sha }}
            ${{ env.IMAGE_BASE }}/superset:latest
          cache-from: type=gha
          cache-to: type=gha,mode=max

  integration-test:
    needs: [build-services, build-dashboard]
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
    runs-on: self-hosted-gremlin
    permissions:
      contents: read
      packages: read
    steps:
      - uses: actions/checkout@v5

      - name: Install kubectl
        run: |
          curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
          chmod +x kubectl
          sudo mv kubectl /usr/local/bin/kubectl
          kubectl version --client

      - name: Install Helm
        run: |
          curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | sudo bash
          helm version

      - name: Install pipeline dependencies
        run: |
          sudo apt-get update -qq && sudo apt-get install -y -qq gettext-base python3 python3-pip > /dev/null 2>&1
          envsubst --version
          pip3 install httpx asyncpg pytest pytest-asyncio --quiet 2>/dev/null || true

      - name: Configure kubectl
        run: |
          # Use in-cluster service account if available, otherwise skip
          if [ -f /var/run/secrets/kubernetes.io/serviceaccount/token ]; then
            kubectl config set-cluster in-cluster \
              --server=https://kubernetes.default.svc \
              --certificate-authority=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
            kubectl config set-credentials runner \
              --token="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)"
            kubectl config set-context runner --cluster=in-cluster --user=runner
            kubectl config use-context runner
            echo "Using in-cluster service account"
          else
            echo "No in-cluster credentials found — kubectl must be pre-configured"
          fi
          kubectl cluster-info || echo "WARNING: kubectl cannot reach cluster API"

      - name: Run integration tests
        run: |
          bash infra/inttest/run_pipeline.sh \
            --image-tag ${{ github.sha }} \
            --results-file inttest-results.json
      - name: Upload results
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: inttest-results
          path: inttest-results.json

  beta-gate:
    needs: [integration-test]
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
    runs-on: self-hosted-gremlin
    permissions:
      contents: read
      packages: read
    steps:
      - uses: actions/checkout@v5

      - name: Install kubectl
        run: |
          if ! command -v kubectl &> /dev/null; then
            curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
            chmod +x kubectl
            sudo mv kubectl /usr/local/bin/kubectl
          fi
          kubectl version --client

      - name: Install Helm
        run: |
          if ! command -v helm &> /dev/null; then
            curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | sudo bash
          fi
          helm version

      - name: Configure kubectl
        run: |
          if [ -f /var/run/secrets/kubernetes.io/serviceaccount/token ]; then
            kubectl config set-cluster in-cluster \
              --server=https://kubernetes.default.svc \
              --certificate-authority=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
            kubectl config set-credentials runner \
              --token="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)"
            kubectl config set-context runner --cluster=in-cluster --user=runner
            kubectl config use-context runner
          fi
          kubectl cluster-info || echo "WARNING: kubectl cannot reach cluster API"

      - name: Run beta gate (deploy → test → promote)
        run: |
          bash infra/inttest/promote.sh \
            --image-tag ${{ github.sha }} \
            --results-file beta-gate-results.json

      - name: Upload beta gate results
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: beta-gate-results
          path: beta-gate-results.json
