name: CI

on:
  push:
    branches: [develop]
  pull_request:
    branches: [develop]
  workflow_dispatch:

env:
  CARGO_TERM_COLOR: always
  RUST_BACKTRACE: 1
  NIGHTLY: "nightly-2026-03-01"
  MCDC_RUSTFLAGS: "--cfg coverage_nightly -Z coverage-options=condition"
  SERVER_RUSTFLAGS: "--cfg coverage_nightly"
  CARGO_PROFILE_DEV_DEBUG: line-tables-only

jobs:
  # ─── Gate: Lint (fmt + clippy) ───
  lint:
    name: Lint
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@nightly
        with:
          toolchain: ${{ env.NIGHTLY }}
          components: rustfmt, clippy
      - uses: Swatinem/rust-cache@v2
      - uses: arduino/setup-protoc@v3
        with:
          repo-token: ${{ secrets.GITHUB_TOKEN }}
      - name: Check formatting
        run: cargo +${{ env.NIGHTLY }} fmt --all -- --check
      - name: Clippy (zero warnings)
        run: >
          cargo +${{ env.NIGHTLY }} clippy
          --all-targets --all-features --workspace -- -D warnings

  # ─── Stable Checks (MSRV + doc tests, non-blocking) ───
  stable-checks:
    name: Stable Checks
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
        with:
          toolchain: "1.92"
      - uses: Swatinem/rust-cache@v2
      - uses: arduino/setup-protoc@v3
        with:
          repo-token: ${{ secrets.GITHUB_TOKEN }}
      - name: MSRV check (key crates)
        run: cargo +1.92 check -p reovim-app -p reovim-kernel -p reovim-server
      - name: Doc tests
        run: cargo +1.92 test --doc --workspace

  # ─── Build: MC/DC variant (starts immediately, no lint gate) ───
  build-mcdc:
    name: Build (MC/DC)
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: ./.github/actions/setup-coverage
        with:
          nightly: ${{ env.NIGHTLY }}
          github-token: ${{ secrets.GITHUB_TOKEN }}
      - name: Build workspace + tests + bins (instrumented)
        run: |
          export RUSTFLAGS="${{ env.MCDC_RUSTFLAGS }}"
          eval "$(cargo +${{ env.NIGHTLY }} llvm-cov show-env --sh)"
          cargo +${{ env.NIGHTLY }} build --workspace --tests --bins \
            --exclude reovim-module-macros \
            --exclude reovim-driver-ffi-python \
            --exclude reovim-bench \
            --exclude perf-report \
            --exclude reovim-server
      - name: Build FFI modules (instrumented)
        run: |
          export RUSTFLAGS="${{ env.MCDC_RUSTFLAGS }}"
          eval "$(cargo +${{ env.NIGHTLY }} llvm-cov show-env --sh)"
          cargo +${{ env.NIGHTLY }} build -p reovim-module-treesitter-rust --features dynamic
          cargo +${{ env.NIGHTLY }} build -p reovim-module-treesitter-markdown --features dynamic
      - name: Save build cache
        uses: actions/cache/save@v4
        with:
          path: |
            target/
            ~/.cargo/registry
            ~/.cargo/git
          key: v2-mcdc-${{ hashFiles('Cargo.lock') }}

  # ─── Build: Server variant (starts immediately, no lint gate) ───
  build-server:
    name: Build (Server)
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: ./.github/actions/setup-coverage
        with:
          nightly: ${{ env.NIGHTLY }}
          github-token: ${{ secrets.GITHUB_TOKEN }}
      - name: Build server + app binary + tests (instrumented)
        run: |
          export RUSTFLAGS="${{ env.SERVER_RUSTFLAGS }}"
          eval "$(cargo +${{ env.NIGHTLY }} llvm-cov show-env --sh)"
          cargo +${{ env.NIGHTLY }} build -p reovim-server -p reovim-app --tests --bins
      - name: Save build cache
        uses: actions/cache/save@v4
        with:
          path: |
            target/
            ~/.cargo/registry
            ~/.cargo/git
          key: v2-server-${{ hashFiles('Cargo.lock') }}

  # ─── Test: MC/DC Unit Tests (sharded) ───
  test-mcdc-unit:
    name: MC/DC Unit (${{ matrix.partition }}/2)
    runs-on: ubuntu-latest
    needs: [lint, build-mcdc]
    strategy:
      fail-fast: false
      matrix:
        partition: [1, 2]
    steps:
      - uses: actions/checkout@v4
      - uses: ./.github/actions/setup-coverage
        with:
          nightly: ${{ env.NIGHTLY }}
          install-nextest: "true"
          github-token: ${{ secrets.GITHUB_TOKEN }}
      - name: Restore build cache
        uses: actions/cache/restore@v4
        with:
          path: |
            target/
            ~/.cargo/registry
            ~/.cargo/git
          key: v2-mcdc-${{ hashFiles('Cargo.lock') }}
      - name: Clean stale coverage data
        run: |
          find target -name '*.profraw' -delete 2>/dev/null || true
          # Remove stale server binaries — LLVM #119558 SIGSEGV on
          # MC/DC data from async trait impls in grpc service files.
          find target -name '*reovim_server*' -delete 2>/dev/null || true
          rm -f target/debug/reovim
      - name: Run unit tests with coverage
        run: |
          export RUSTFLAGS="${{ env.MCDC_RUSTFLAGS }}"
          cargo +${{ env.NIGHTLY }} llvm-cov nextest --lib --workspace \
            --profile ci \
            --partition count:${{ matrix.partition }}/2 \
            --exclude reovim-module-macros \
            --exclude reovim-driver-ffi-python \
            --exclude reovim-bench \
            --exclude perf-report \
            --exclude reovim-server \
            --exclude reovim-driver-display \
            --lcov --output-path mcdc-unit.info
      - name: Filter test code
        run: ./scripts/lcov-filter-tests.sh mcdc-unit.info
      - uses: actions/upload-artifact@v4
        with:
          name: mcdc-unit-lcov-${{ matrix.partition }}
          path: mcdc-unit.info

  # ─── Test: MC/DC Integration Tests ───
  test-mcdc-integration:
    name: MC/DC Integration
    runs-on: ubuntu-latest
    needs: [lint, build-mcdc]
    steps:
      - uses: actions/checkout@v4
      - uses: ./.github/actions/setup-coverage
        with:
          nightly: ${{ env.NIGHTLY }}
          install-nextest: "true"
          github-token: ${{ secrets.GITHUB_TOKEN }}
      - name: Restore build cache
        uses: actions/cache/restore@v4
        with:
          path: |
            target/
            ~/.cargo/registry
            ~/.cargo/git
          key: v2-mcdc-${{ hashFiles('Cargo.lock') }}
      - name: Clean stale coverage data
        run: |
          find target -name '*.profraw' -delete 2>/dev/null || true
          find target -name '*reovim_server*' -delete 2>/dev/null || true
          rm -f target/debug/reovim
      - name: Ensure server binary + FFI modules exist
        run: |
          export RUSTFLAGS="${{ env.MCDC_RUSTFLAGS }}"
          eval "$(cargo +${{ env.NIGHTLY }} llvm-cov show-env --sh)"
          cargo +${{ env.NIGHTLY }} build -p reovim-app --bins
          cargo +${{ env.NIGHTLY }} build -p reovim-module-treesitter-rust --features dynamic
          cargo +${{ env.NIGHTLY }} build -p reovim-module-treesitter-markdown --features dynamic
          ls -la target/debug/reovim
      - name: Run integration tests with coverage
        run: |
          export RUSTFLAGS="${{ env.MCDC_RUSTFLAGS }}"
          cargo +${{ env.NIGHTLY }} llvm-cov nextest --test '*' --workspace \
            --profile ci \
            --exclude reovim-module-macros \
            --exclude reovim-driver-ffi-python \
            --exclude reovim-bench \
            --exclude perf-report \
            --exclude reovim-server \
            --exclude reovim-driver-display \
            --lcov --output-path mcdc-integration.info
      - name: Filter test code
        run: ./scripts/lcov-filter-tests.sh mcdc-integration.info
      - uses: actions/upload-artifact@v4
        with:
          name: mcdc-integration-lcov
          path: mcdc-integration.info

  # ─── Test: Server Line Coverage ───
  test-server:
    name: Server Coverage
    runs-on: ubuntu-latest
    needs: [lint, build-server]
    steps:
      - uses: actions/checkout@v4
      - uses: ./.github/actions/setup-coverage
        with:
          nightly: ${{ env.NIGHTLY }}
          install-nextest: "true"
          github-token: ${{ secrets.GITHUB_TOKEN }}
      - name: Restore build cache
        uses: actions/cache/restore@v4
        with:
          path: |
            target/
            ~/.cargo/registry
            ~/.cargo/git
          key: v2-server-${{ hashFiles('Cargo.lock') }}
      - name: Clean stale coverage data
        run: find target -name '*.profraw' -delete 2>/dev/null || true
      - name: Ensure server binary exists
        run: |
          export RUSTFLAGS="${{ env.SERVER_RUSTFLAGS }}"
          eval "$(cargo +${{ env.NIGHTLY }} llvm-cov show-env --sh)"
          cargo +${{ env.NIGHTLY }} build -p reovim-app --bins
          ls -la target/debug/reovim
      - name: Run server tests with coverage
        run: |
          export RUSTFLAGS="${{ env.SERVER_RUSTFLAGS }}"
          cargo +${{ env.NIGHTLY }} llvm-cov nextest -p reovim-server \
            --profile ci \
            --lcov --output-path server-lcov.info
      - name: Filter test code
        run: ./scripts/lcov-filter-tests.sh server-lcov.info
      - uses: actions/upload-artifact@v4
        with:
          name: server-lcov
          path: server-lcov.info

  # ─── Upload: Merge + Codecov ───
  coverage-upload:
    name: Coverage Upload
    runs-on: ubuntu-latest
    needs: [test-mcdc-unit, test-mcdc-integration, test-server]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/download-artifact@v4
        with:
          name: mcdc-unit-lcov-1
      - name: Rename shard 1
        run: mv mcdc-unit.info mcdc-unit-1.info
      - uses: actions/download-artifact@v4
        with:
          name: mcdc-unit-lcov-2
      - name: Rename shard 2
        run: mv mcdc-unit.info mcdc-unit-2.info
      - uses: actions/download-artifact@v4
        with:
          name: mcdc-integration-lcov
      - uses: actions/download-artifact@v4
        with:
          name: server-lcov
      - name: Merge reports
        run: cat mcdc-unit-1.info mcdc-unit-2.info mcdc-integration.info server-lcov.info > lcov.info
      - name: Generate reports
        run: |
          ./scripts/coverage-report.sh lcov.info
          mv COVERAGE.md COVERAGE-workspace.md
      - uses: actions/upload-artifact@v4
        with:
          name: coverage-reports
          path: COVERAGE-workspace.md
      - name: Upload to Codecov
        uses: codecov/codecov-action@v5
        with:
          files: lcov.info
          flags: coverage
          fail_ci_if_error: true
        env:
          CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
