#!/bin/bash

set -e

echo "🔍 Running pre-commit checks..."

# Track time
START_TIME=$(date +%s)

# Get current branch
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "main")

# Get all staged files
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACMR)

# Detect what types of files changed
HAS_ELIXIR_FILES=$(echo "$STAGED_FILES" | grep -E '\.(ex|exs)$' || true)
HAS_CONFIG_FILES=$(echo "$STAGED_FILES" | grep -E '^config/.*\.exs$' || true)
HAS_MIX_FILES=$(echo "$STAGED_FILES" | grep -E '^mix\.(exs|lock)$' || true)
HAS_DELETED_MODULES=$(git diff --cached --diff-filter=D --name-only | grep -E '\.(ex|exs)$' || true)
HAS_RENAMED_MODULES=$(git diff --cached --diff-filter=R --name-only | grep -E '\.(ex|exs)$' || true)
HAS_LISP_CHANGES=$(echo "$STAGED_FILES" | grep -E '^lib/ptc_runner/lisp/|^docs/ptc-lisp-specification\.md$' || true)

# Determine if tests should run
SHOULD_RUN_TESTS=false
SKIP_REASON=""

if [ -n "$HAS_ELIXIR_FILES" ] || [ -n "$HAS_CONFIG_FILES" ] || [ -n "$HAS_MIX_FILES" ]; then
  SHOULD_RUN_TESTS=true
else
  SKIP_REASON="No Elixir/config/mix files changed"
fi

# Handle deleted/renamed modules - need clean build to catch stale .beam files
if [ -n "$HAS_DELETED_MODULES" ] || [ -n "$HAS_RENAMED_MODULES" ]; then
  echo "  ⚠️  Detected deleted/renamed Elixir modules - cleaning build..."
  [ -n "$HAS_DELETED_MODULES" ] && echo "$HAS_DELETED_MODULES" | sed 's/^/    - (deleted) /'
  [ -n "$HAS_RENAMED_MODULES" ] && echo "$HAS_RENAMED_MODULES" | sed 's/^/    - (renamed) /'
  mix clean --deps > /dev/null 2>&1
  mix deps.compile > /dev/null 2>&1
  echo "  ✅ Clean build completed"
fi

# 1. Format check (only if Elixir files changed)
if [ -n "$HAS_ELIXIR_FILES" ]; then
  echo "  ⏳ Checking code formatting..."
  if ! mix format --check-formatted > /dev/null 2>&1; then
    echo "  ❌ Code not formatted. Run: mix format"
    exit 1
  fi
  echo "  ✅ Code formatted"
else
  echo "  ⏭️  Skipping format check (no Elixir files)"
fi

# 2. Compilation check (only if Elixir/config/mix files changed)
if [ "$SHOULD_RUN_TESTS" = true ]; then
  echo "  ⏳ Compiling with warnings as errors..."
  if ! mix compile --warnings-as-errors > /dev/null 2>&1; then
    echo "  ❌ Compilation failed or warnings present"
    echo "  Run: mix compile"
    exit 1
  fi
  echo "  ✅ Compilation successful"
else
  echo "  ⏭️  Skipping compilation ($SKIP_REASON)"
fi

# 3. Credo check (only if Elixir files changed)
if [ -n "$HAS_ELIXIR_FILES" ]; then
  echo "  ⏳ Running Credo..."
  if ! mix credo --strict > /dev/null 2>&1; then
    echo "  ❌ Credo issues found. Run: mix credo --strict"
    exit 1
  fi
  echo "  ✅ Credo passed"
else
  echo "  ⏭️  Skipping Credo (no Elixir files)"
fi

# 4. Spec validation (only if lisp-related files changed)
if [ -n "$HAS_LISP_CHANGES" ]; then
  echo "  ⏳ Validating PTC-Lisp specification..."
  if ! mix ptc.validate_spec > /dev/null 2>&1; then
    echo "  ❌ Spec validation failed. Run: mix ptc.validate_spec"
    exit 1
  fi
  echo "  ✅ Spec validation passed"
else
  echo "  ⏭️  Skipping spec validation (no lisp changes)"
fi

# 5. Run tests (only if code could affect behavior)
if [ "$SHOULD_RUN_TESTS" = true ]; then
  # Check for changed test files to run them specifically
  changed_test_files=$(echo "$STAGED_FILES" | grep "^test/.*_test\.exs$" || true)

  if [ -n "$changed_test_files" ]; then
    echo "  ⏳ Running tests for changed files..."
    TEST_FAILED=false
    for file in $changed_test_files; do
      echo "    Testing: $file"
      if ! mix test "$file" > /dev/null 2>&1; then
        echo "    ❌ Tests failed for $file"
        TEST_FAILED=true
      fi
    done

    if [ "$TEST_FAILED" = true ]; then
      if [ "$CURRENT_BRANCH" = "main" ]; then
        echo "  ❌ Tests failed - commit blocked on main branch"
        exit 1
      else
        echo "  ⚠️  Tests failing on branch '$CURRENT_BRANCH' - commit allowed, fix before merge"
      fi
    else
      echo "  ✅ Changed tests pass"
    fi
  else
    echo "  ℹ️  No test files changed (run 'mix test' before push)"
  fi
else
  echo "  ⏭️  Skipping tests ($SKIP_REASON)"
fi

# Calculate elapsed time
END_TIME=$(date +%s)
ELAPSED=$((END_TIME - START_TIME))

echo ""
echo "✅ All pre-commit checks passed in ${ELAPSED}s"
echo ""

# Ensure <10s
if [ $ELAPSED -gt 10 ]; then
  echo "⚠️  Warning: Pre-commit took ${ELAPSED}s (target: <10s)"
fi
