name: Cache Benchmark Harness Binary
description: >
  Build and cache the benchmark-harness binary with intelligent caching based on source hashes.
  Generates cache keys based on harness source + kreuzberg dependency + Cargo files,
  restores from cache if available, builds if needed, and saves to cache.
  Validates artifacts after restore or build to ensure integrity.

inputs:
  cache-version:
    description: "Manual version for cache invalidation"
    required: false
    default: "v1"

  build-profile:
    description: "Build profile (release, debug)"
    required: false
    default: "release"

outputs:
  cache-hit:
    description: "Boolean indicating exact cache hit"
    value: ${{ steps.cache-restore.outputs.cache-hit }}

  cache-key:
    description: "The cache key used"
    value: ${{ steps.generate-cache-key.outputs.cache-key }}

  binary-path:
    description: "Path to the built/cached benchmark-harness binary"
    value: ${{ steps.validate-binary.outputs.binary-path }}

runs:
  using: composite
  steps:
    # Validate inputs
    - name: Validate inputs
      shell: bash
      env:
        BUILD_PROFILE: ${{ inputs.build-profile }}
      run: |
        set -euo pipefail

        # Validate build profile
        valid_profiles=("release" "debug")
        if [[ ! " ${valid_profiles[@]} " =~ " ${BUILD_PROFILE} " ]]; then
          echo "❌ Error: build-profile must be one of: ${valid_profiles[*]}"
          exit 1
        fi

        echo "✓ Validation passed"
        echo "  Build profile: $BUILD_PROFILE"
        echo "  Cache version: ${{ inputs.cache-version }}"

    # Compute hash for benchmark-harness sources
    - name: Compute benchmark-harness source hash
      id: harness-hash
      shell: bash
      run: |
        set -euo pipefail

        echo "=== Computing Benchmark Harness Source Hash ==="

        # Compute hash for harness source files and Cargo.toml
        HARNESS_HASH=$(scripts/ci/cache/compute-hash.sh \
          "tools/benchmark-harness/src/**" \
          "tools/benchmark-harness/Cargo.toml" \
          2>&1 | grep "^[a-f0-9]*$")

        if [[ -z "$HARNESS_HASH" ]]; then
          echo "❌ Failed to compute harness source hash"
          exit 1
        fi

        echo "harness-hash=$HARNESS_HASH" >> "$GITHUB_OUTPUT"
        echo "✓ Harness source hash: $HARNESS_HASH"

    # Compute hash for kreuzberg dependency
    - name: Compute kreuzberg dependency hash
      id: kreuzberg-hash
      shell: bash
      run: |
        set -euo pipefail

        echo "=== Computing Kreuzberg Dependency Hash ==="

        # Compute hash for kreuzberg crate (dependency)
        KREUZBERG_HASH=$(scripts/ci/cache/compute-hash.sh --dirs \
          "crates/kreuzberg" \
          2>&1 | grep "^[a-f0-9]*$")

        if [[ -z "$KREUZBERG_HASH" ]]; then
          echo "❌ Failed to compute kreuzberg dependency hash"
          exit 1
        fi

        echo "kreuzberg-hash=$KREUZBERG_HASH" >> "$GITHUB_OUTPUT"
        echo "✓ Kreuzberg dependency hash: $KREUZBERG_HASH"

    # Compute hash for Cargo files
    - name: Compute Cargo files hash
      id: cargo-hash
      shell: bash
      run: |
        set -euo pipefail

        echo "=== Computing Cargo Files Hash ==="

        # Compute hash for Cargo.lock
        CARGO_HASH=$(scripts/ci/cache/compute-hash.sh --files Cargo.lock 2>&1 | grep "^[a-f0-9]*$")

        if [[ -z "$CARGO_HASH" ]]; then
          echo "❌ Failed to compute Cargo files hash"
          exit 1
        fi

        echo "cargo-hash=$CARGO_HASH" >> "$GITHUB_OUTPUT"
        echo "✓ Cargo files hash: $CARGO_HASH"

    # Generate cache key
    - name: Generate cache key
      id: generate-cache-key
      shell: bash
      env:
        BUILD_PROFILE: ${{ inputs.build-profile }}
        HARNESS_HASH: ${{ steps.harness-hash.outputs.harness-hash }}
        KREUZBERG_HASH: ${{ steps.kreuzberg-hash.outputs.kreuzberg-hash }}
        CARGO_HASH: ${{ steps.cargo-hash.outputs.cargo-hash }}
        CACHE_VERSION: ${{ inputs.cache-version }}
      run: |
        set -euo pipefail

        echo "=== Cache Key Generated ==="

        # Build cache key following format:
        # harness-{profile}-{platform}-src-{harness-hash}-kreuzberg-{kreuzberg-hash}-cargo-{cargo-hash}-v{version}
        CACHE_KEY="harness-${BUILD_PROFILE}-$(uname -m)-src-${HARNESS_HASH}-kreuzberg-${KREUZBERG_HASH}-cargo-${CARGO_HASH}-${CACHE_VERSION}"

        echo "cache-key=$CACHE_KEY" >> "$GITHUB_OUTPUT"

        echo "Full key: $CACHE_KEY"
        echo ""
        echo "Key components:"
        echo "  Profile:         $BUILD_PROFILE"
        echo "  Platform:        $(uname -m)"
        echo "  Harness hash:    $HARNESS_HASH"
        echo "  Kreuzberg hash:  $KREUZBERG_HASH"
        echo "  Cargo hash:      $CARGO_HASH"
        echo "  Cache version:   $CACHE_VERSION"

    # Determine target path based on profile
    - name: Determine target paths
      id: target-paths
      shell: bash
      env:
        BUILD_PROFILE: ${{ inputs.build-profile }}
      run: |
        set -euo pipefail

        echo "=== Determining Target Paths ==="

        case "$BUILD_PROFILE" in
          release)
            TARGET_DIR="target/release"
            ;;
          debug)
            TARGET_DIR="target/debug"
            ;;
          *)
            echo "❌ Invalid build profile: $BUILD_PROFILE"
            exit 1
            ;;
        esac

        echo "target-dir=$TARGET_DIR" >> "$GITHUB_OUTPUT"
        echo "✓ Target directory: $TARGET_DIR"

    # Detect architecture for cache keys (shell expansion doesn't work in YAML with: context)
    - name: Detect architecture
      id: detect-arch
      shell: bash
      run: echo "arch=$(uname -m)" >> "$GITHUB_OUTPUT"

    # Restore from cache
    - name: Restore benchmark-harness binary from cache
      id: cache-restore
      uses: kreuzberg-dev/actions/cache-binding-artifact@v1
      with:
        binding-name: benchmark-harness
        cache-key: ${{ steps.generate-cache-key.outputs.cache-key }}
        cache-restore-keys: |
          harness-${{ inputs.build-profile }}-${{ steps.detect-arch.outputs.arch }}-src-
          harness-${{ inputs.build-profile }}-${{ steps.detect-arch.outputs.arch }}-
          harness-${{ inputs.build-profile }}-
        cache-paths: |
          ${{ steps.target-paths.outputs.target-dir }}/benchmark-harness
        operation: restore

    # Log cache hit status
    - name: Log cache hit status
      shell: bash
      run: |
        set -euo pipefail

        if [[ "${{ steps.cache-restore.outputs.cache-hit }}" == "true" ]]; then
          echo "✓ Cache HIT - benchmark-harness binary found in cache"
        else
          echo "✗ Cache MISS - Building benchmark-harness from source"
        fi

    # Build if cache miss
    - name: Build benchmark-harness
      id: build
      if: steps.cache-restore.outputs.cache-hit != 'true'
      shell: bash
      env:
        BUILD_PROFILE: ${{ inputs.build-profile }}
      run: |
        set -euo pipefail

        echo "=== Building Benchmark Harness ==="
        echo "Profile: $BUILD_PROFILE"

        # Determine cargo build profile argument
        case "$BUILD_PROFILE" in
          release)
            BUILD_ARG="--release"
            ;;
          debug)
            # Debug is default, no flag needed
            BUILD_ARG=""
            ;;
          *)
            echo "❌ Invalid build profile: $BUILD_PROFILE"
            exit 1
            ;;
        esac

        # Build benchmark-harness
        echo "Running: cargo build --manifest-path tools/benchmark-harness/Cargo.toml $BUILD_ARG"
        if ! cargo build --manifest-path tools/benchmark-harness/Cargo.toml $BUILD_ARG; then
          echo "❌ Build failed for benchmark-harness"
          exit 1
        fi

        echo "✓ Build succeeded"

    # Validate binary exists and is executable
    - name: Validate benchmark-harness binary
      id: validate-binary
      shell: bash
      env:
        BUILD_PROFILE: ${{ inputs.build-profile }}
        TARGET_DIR: ${{ steps.target-paths.outputs.target-dir }}
      run: |
        set -euo pipefail

        echo "=== Validating Benchmark Harness Binary ==="

        BINARY_PATH="${TARGET_DIR}/benchmark-harness"

        # Check if binary exists
        if [[ ! -f "$BINARY_PATH" ]]; then
          echo "❌ Binary not found at: $BINARY_PATH"
          exit 1
        fi

        # Check if binary is executable
        if [[ ! -x "$BINARY_PATH" ]]; then
          echo "❌ Binary is not executable: $BINARY_PATH"
          exit 1
        fi

        # Get binary size and info
        BINARY_SIZE=$(ls -lh "$BINARY_PATH" | awk '{print $5}')
        BINARY_PERMS=$(ls -l "$BINARY_PATH" | awk '{print $1}')

        echo "binary-path=$BINARY_PATH" >> "$GITHUB_OUTPUT"

        echo "✓ Binary validation passed"
        echo "  Path:        $BINARY_PATH"
        echo "  Size:        $BINARY_SIZE"
        echo "  Permissions: $BINARY_PERMS"

    # Save to cache if build occurred
    - name: Save benchmark-harness binary to cache
      if: steps.cache-restore.outputs.cache-hit != 'true'
      uses: kreuzberg-dev/actions/cache-binding-artifact@v1
      with:
        binding-name: benchmark-harness
        cache-key: ${{ steps.generate-cache-key.outputs.cache-key }}
        cache-paths: |
          ${{ steps.target-paths.outputs.target-dir }}/benchmark-harness
        operation: save

    # Summary
    - name: Summary
      if: always()
      shell: bash
      run: |
        set -euo pipefail

        echo ""
        echo "=== Build and Cache Summary ==="
        echo "Build Profile:   ${{ inputs.build-profile }}"
        echo "Platform:        $(uname -m)"
        echo "Cache Hit:       ${{ steps.cache-restore.outputs.cache-hit == 'true' && 'Yes' || 'No' }}"
        echo "Cache Key:       ${{ steps.generate-cache-key.outputs.cache-key }}"
        echo "Binary Path:     ${{ steps.validate-binary.outputs.binary-path }}"
        echo ""
        echo "Hashes:"
        echo "  Harness:       ${{ steps.harness-hash.outputs.harness-hash }}"
        echo "  Kreuzberg:     ${{ steps.kreuzberg-hash.outputs.kreuzberg-hash }}"
        echo "  Cargo:         ${{ steps.cargo-hash.outputs.cargo-hash }}"
