name: CI

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

env:
  CARGO_TERM_COLOR: always

jobs:
  build:
    name: Build & Test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install Rust
        uses: dtolnay/rust-toolchain@stable

      - name: Cache cargo
        uses: Swatinem/rust-cache@v2

      - name: Build
        run: cargo build --locked

      - name: Test
        run: cargo test

  bench:
    name: Benchmark
    runs-on: ubuntu-latest
    permissions:
      contents: write
    steps:
      - uses: actions/checkout@v4

      - name: Install Rust
        uses: dtolnay/rust-toolchain@stable

      - name: Cache cargo
        uses: Swatinem/rust-cache@v2

      - name: Build (release)
        run: cargo build --release

      - name: Run benchmarks
        run: bench/run.sh full bench/results/latest.json

      - name: Commit results
        if: github.event_name == 'push'
        run: |
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"
          git add bench/results/latest.json
          git diff --cached --quiet || git commit -m "bench: update results for $(git rev-parse --short HEAD)"
          git push

      - name: Upload results
        uses: actions/upload-artifact@v4
        with:
          name: bench-${{ github.sha }}
          path: bench/results/latest.json

      - name: Format summary
        id: summary
        run: |
          python3 -c "
          import json
          d = json.load(open('bench/results/latest.json'))
          w = d['workloads']

          def fmt(v):
              return f'{v/1024:.1f} GB/s' if v >= 1000 else f'{v:.0f} MB/s'
          def overhead(d, r):
              return f'{r/d*100:.0f}%' if d > 0 else 'n/a'
          def mult(d, r):
              return f'{r/max(d,1):.1f}x'

          lines = []
          lines.append('### Benchmark Results')
          lines.append(f'**Git:** \`{d[\"git_rev\"]}\`')
          lines.append('')

          # Throughput table
          has_tls = w['stream_up'].get('relay_tls') is not None
          hdr = '| Workload | Direct | Relay | Retained |'
          sep = '|----------|--------|-------|----------|'
          if has_tls:
              hdr += ' TLS | Retained |'
              sep += '-----|----------|'
          lines.append(hdr)
          lines.append(sep)
          for name, label in [('stream_up','Stream up'),('stream_down','Stream down'),('terminal_ui','Terminal UI'),('mixed','Mixed')]:
              dr = w[name]['direct']['throughput_mbps']
              rr = w[name]['relay']['throughput_mbps']
              row = f'| {label} | {fmt(dr)} | {fmt(rr)} | {overhead(dr,rr)} |'
              if has_tls:
                  tr = w[name]['relay_tls']['throughput_mbps']
                  row += f' {fmt(tr)} | {overhead(dr,tr)} |'
              lines.append(row)
          lines.append('')

          # Latency table
          lines.append('| Workload | Direct p50 | Relay p50 | Overhead |')
          lines.append('|----------|-----------|-----------|----------|')
          for name, label in [('interactive','Interactive'),('terminal_ui','Terminal UI'),('connection_setup','Conn setup')]:
              dp = w[name]['direct']['latency']['p50_us']
              rp = w[name]['relay']['latency']['p50_us']
              lines.append(f'| {label} | {dp} us | {rp} us | {mult(dp,rp)} |')
          lines.append('')

          # Concurrency table
          hdr = '| Concurrency | Direct | Relay |'
          sep = '|-------------|--------|-------|'
          if has_tls:
              hdr += ' TLS |'
              sep += '-----|'
          lines.append(hdr)
          lines.append(sep)
          for p in d['concurrency_scaling']:
              row = f'| n={p[\"connections\"]} | {fmt(p[\"direct_mbps\"])} | {fmt(p[\"relay_mbps\"])} |'
              if has_tls and p.get('relay_tls_mbps') is not None:
                  row += f' {fmt(p[\"relay_tls_mbps\"])} |'
              lines.append(row)

          summary = '\n'.join(lines)
          print(summary)
          with open('bench-summary.md', 'w') as f:
              f.write(summary)
          "

      - name: Post to job summary
        run: cat bench-summary.md >> "$GITHUB_STEP_SUMMARY"

      - name: Comment on PR
        if: github.event_name == 'pull_request'
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs');
            const body = fs.readFileSync('bench-summary.md', 'utf8');
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: body
            });

  terraform:
    name: Terraform
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: deploy
    env:
      AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
      AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
      TF_VAR_gandi_api_key: ${{ secrets.GANDI_API_KEY }}
      TF_VAR_certbot_email: ${{ secrets.CERTBOT_EMAIL }}
      TF_VAR_ssh_public_key_path: /dev/null
      TF_VAR_ssh_private_key_path: /dev/null
    steps:
      - uses: actions/checkout@v4

      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v3

      - name: Terraform Format Check
        run: terraform fmt -check -recursive

      - name: Terraform Init
        run: terraform init

      - name: Terraform Validate
        run: terraform validate

      - name: Terraform Plan
        if: github.event_name == 'pull_request'
        id: plan
        run: terraform plan -no-color -input=false
        continue-on-error: true

      - name: Post Plan to PR
        if: github.event_name == 'pull_request'
        uses: actions/github-script@v7
        with:
          script: |
            const plan = `${{ steps.plan.outputs.stdout }}`;
            const truncated = plan.length > 60000
              ? plan.substring(0, 60000) + '\n\n... (truncated)'
              : plan;
            const body = `#### Terraform Plan 📋
            \`\`\`
            ${truncated}
            \`\`\`
            *Status: ${{ steps.plan.outcome }}*`;
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: body
            });

      - name: Terraform Plan Status
        if: steps.plan.outcome == 'failure'
        run: exit 1
