name: 🚀 Deploy
on:
    push:
        branches:
            - main
    pull_request: {}

permissions:
    actions: write
    contents: read

jobs:
    cancel:
        name: 🛑 Cancel Previous Runs
        runs-on: ubuntu-latest
        steps:
            - uses: styfle/cancel-workflow-action@0.12.1

    test:
        name: 🧪 Test
        needs: [cancel]
        runs-on: ubuntu-latest

        services:
            postgres:
                image: postgres:15
                env:
                    POSTGRES_USER: test
                    POSTGRES_PASSWORD: test
                    POSTGRES_DB: brackt_test
                options: >-
                    --health-cmd pg_isready
                    --health-interval 10s
                    --health-timeout 5s
                    --health-retries 5
                ports:
                    - 5432:5432

        steps:
            - name: ⬇️ Checkout repo
              uses: actions/checkout@v4

            - name: ⎔ Setup node
              uses: actions/setup-node@v4
              with:
                  node-version-file: '.nvmrc'
                  cache: 'npm'

            - name: 📥 Install dependencies
              run: npm ci

            - name: 🧪 Run unit tests
              run: npm run test:run
              env:
                  DATABASE_URL: postgresql://test:test@localhost:5432/brackt_test
                  NODE_OPTIONS: --max-old-space-size=4096

    typecheck:
        name: ʦ TypeScript
        needs: [cancel]
        runs-on: ubuntu-latest
        steps:
            - name: ⬇️ Checkout repo
              uses: actions/checkout@v4

            - name: ⎔ Setup node
              uses: actions/setup-node@v4
              with:
                  node-version-file: '.nvmrc'
                  cache: 'npm'

            - name: 📥 Install dependencies
              run: npm ci

            - name: 🔎 Type check
              run: npm run typecheck

    lint:
        name: 🔍 Lint
        needs: [cancel]
        runs-on: ubuntu-latest
        steps:
            - name: ⬇️ Checkout repo
              uses: actions/checkout@v4

            - name: ⎔ Setup node
              uses: actions/setup-node@v4
              with:
                  node-version-file: '.nvmrc'
                  cache: 'npm'

            - name: 📥 Install dependencies
              run: npm ci

            - name: 🔍 Lint (oxlint)
              run: npm run lint

    build:
        name: 🐳 Build
        needs: [test, typecheck, lint]
        # only build/deploy main branch on pushes
        if: ${{ github.ref == 'refs/heads/main' && github.event_name == 'push' }}
        runs-on: ubuntu-latest
        steps:
            - name: ⬇️ Checkout repo
              uses: actions/checkout@v4

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

            - name: 🔓 Login to Container Registry
              uses: docker/login-action@v3
              with:
                  registry: ${{ vars.CONTAINER_REGISTRY }}
                  username: ${{ secrets.REGISTRY_USERNAME }}
                  password: ${{ secrets.REGISTRY_PASSWORD }}

            - name: 🗄️ Build and Push to Container Registry
              uses: docker/build-push-action@v5
              with:
                  context: .
                  push: true
                  tags: ${{ vars.CONTAINER_REGISTRY }}/brackt:latest
                  cache-from: type=gha
                  cache-to: type=gha,mode=max

    deploy:
        name: 🚀 Deploy
        runs-on: ubuntu-latest
        needs: [build]
        # only deploy main branch on pushes
        if: ${{ github.ref == 'refs/heads/main' && github.event_name == 'push' }}

        steps:
            - name: 🚀 Deploy app to server
              uses: appleboy/ssh-action@v1.0.3
              env:
                  REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
                  REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
                  CONTAINER_REGISTRY: ${{ vars.CONTAINER_REGISTRY }}
              with:
                  host: ${{ secrets.DEPLOY_HOST }}
                  port: ${{ secrets.DEPLOY_PORT }}
                  username: ${{ secrets.DEPLOY_USER }}
                  key: ${{ secrets.DEPLOY_KEY }}
                  envs: REGISTRY_USERNAME,REGISTRY_PASSWORD,CONTAINER_REGISTRY
                  script: |
                      set -e
                      docker login $CONTAINER_REGISTRY -u $REGISTRY_USERNAME -p $REGISTRY_PASSWORD
                      cd brackt
                      docker compose pull
                      if ! docker compose up --no-deps migrate; then
                        echo "Migration failed:"
                        docker compose logs migrate
                        exit 1
                      fi
                      docker compose up -d --remove-orphans
