#!/bin/sh

# =============================================================================
# GIT WORKTREE ENVIRONMENT CLEANUP
# =============================================================================
# Git automatically sets GIT_DIR (and CWD to the working tree root) before
# running hooks -- even in worktrees. We do NOT need to manually parse .git
# files or export GIT_DIR/GIT_WORK_TREE.
#
# However, external tools (IDEs, agents, parent shells) may leave stale
# GIT_DIR/GIT_WORK_TREE values in the environment. If these point to a
# different repo or worktree, git commands in this hook would target the
# wrong repository. Unsetting them lets git re-resolve the correct values
# from the working directory.
# =============================================================================
unset GIT_DIR
unset GIT_WORK_TREE

# =============================================================================
# SAFETY CHECK: Detect and fix corrupted core.worktree configuration
# =============================================================================
# core.worktree lives in the SHARED .git/config (not per-worktree). If any
# process accidentally writes it (e.g., running `git init` with a leaked
# GIT_WORK_TREE), ALL repos and worktrees see the wrong working tree root,
# causing files from one worktree to "leak" into others.
#
# This check runs from both main repo and worktree contexts since the config
# is shared and corruption can happen from either.
CORE_WORKTREE=$(git config --get core.worktree 2>/dev/null || true)
if [ -n "$CORE_WORKTREE" ]; then
  echo "Warning: Detected corrupted core.worktree setting ('$CORE_WORKTREE'), removing it..."
  if ! git config --unset core.worktree 2>/dev/null; then
    echo "Warning: Failed to unset core.worktree. Manual intervention may be needed."
  fi
fi

echo "Running pre-commit checks..."

# =============================================================================
# VERSION SYNC - Keep all version references in sync with root package.json
# =============================================================================

# Check if package.json is staged
if git diff --cached --name-only | grep -q "^package.json$"; then
  echo "package.json changed, syncing version to all files..."

  # Extract version from root package.json
  VERSION=$(node -p "require('./package.json').version")

  if [ -n "$VERSION" ]; then
    # Sync to apps/frontend/package.json
    if [ -f "apps/frontend/package.json" ]; then
      node -e "
        const fs = require('fs');
        const pkg = require('./apps/frontend/package.json');
        if (pkg.version !== '$VERSION') {
          pkg.version = '$VERSION';
          fs.writeFileSync('./apps/frontend/package.json', JSON.stringify(pkg, null, 2) + '\n');
          console.log('  Updated apps/frontend/package.json to $VERSION');
        }
      "
      git add apps/frontend/package.json
    fi

    # Sync to apps/backend/__init__.py
    if [ -f "apps/backend/__init__.py" ]; then
      sed -i.bak "s/__version__ = \"[^\"]*\"/__version__ = \"$VERSION\"/" apps/backend/__init__.py
      rm -f apps/backend/__init__.py.bak
      git add apps/backend/__init__.py
      echo "  Updated apps/backend/__init__.py to $VERSION"
    fi

    # Sync to README.md - section-aware updates (stable vs beta)
    if [ -f "README.md" ]; then
      # Escape hyphens for shields.io badge format (shields.io uses -- for literal hyphens)
      ESCAPED_VERSION=$(echo "$VERSION" | sed 's/-/--/g')

      # Detect if this is a prerelease (contains - after base version, e.g., 2.7.2-beta.10)
      if echo "$VERSION" | grep -q '-'; then
        # PRERELEASE: Update only beta sections
        echo "  Detected PRERELEASE version: $VERSION"

        # Update beta version badge (orange)
        sed -i.bak "s/beta-[0-9]*\.[0-9]*\.[0-9]*\(--[a-z]*\.[0-9]*\)*-orange/beta-$ESCAPED_VERSION-orange/g" README.md

        # Update beta version badge link (within BETA_VERSION_BADGE section)
        sed -i.bak '/<!-- BETA_VERSION_BADGE -->/,/<!-- BETA_VERSION_BADGE_END -->/s|releases/tag/v[0-9.a-z-]*)|releases/tag/v'"$VERSION"')|g' README.md

        # Update beta download links (within BETA_DOWNLOADS section only)
        # Use perl for cross-platform compatibility (BSD sed doesn't support {block} syntax)
        for SUFFIX in "win32-x64.exe" "darwin-arm64.dmg" "darwin-x64.dmg" "linux-x86_64.AppImage" "linux-amd64.deb" "linux-x86_64.flatpak"; do
          perl -i -pe 'if (/<!-- BETA_DOWNLOADS -->/ .. /<!-- BETA_DOWNLOADS_END -->/) { s|Auto-Claude-[0-9.a-z-]*-'"$SUFFIX"'\]\(https://github.com/AndyMik90/Auto-Claude/releases/download/v[^/]*/Auto-Claude-[^)]*-'"$SUFFIX"'\)|Auto-Claude-'"$VERSION"'-'"$SUFFIX"'](https://github.com/AndyMik90/Auto-Claude/releases/download/v'"$VERSION"'/Auto-Claude-'"$VERSION"'-'"$SUFFIX"')|g }' README.md
        done
      else
        # STABLE: Update stable sections and top badge
        echo "  Detected STABLE version: $VERSION"

        # Update top version badge (blue) - within TOP_VERSION_BADGE section
        sed -i.bak '/<!-- TOP_VERSION_BADGE -->/,/<!-- TOP_VERSION_BADGE_END -->/s/version-[0-9]*\.[0-9]*\.[0-9]*\(--[a-z]*\.[0-9]*\)*-blue/version-'"$ESCAPED_VERSION"'-blue/g' README.md
        sed -i.bak '/<!-- TOP_VERSION_BADGE -->/,/<!-- TOP_VERSION_BADGE_END -->/s|releases/tag/v[0-9.a-z-]*)|releases/tag/v'"$VERSION"')|g' README.md

        # Update stable version badge (blue) - within STABLE_VERSION_BADGE section
        sed -i.bak '/<!-- STABLE_VERSION_BADGE -->/,/<!-- STABLE_VERSION_BADGE_END -->/s/stable-[0-9]*\.[0-9]*\.[0-9]*\(--[a-z]*\.[0-9]*\)*-blue/stable-'"$ESCAPED_VERSION"'-blue/g' README.md
        sed -i.bak '/<!-- STABLE_VERSION_BADGE -->/,/<!-- STABLE_VERSION_BADGE_END -->/s|releases/tag/v[0-9.a-z-]*)|releases/tag/v'"$VERSION"')|g' README.md

        # Update stable download links (within STABLE_DOWNLOADS section only)
        # Use perl for cross-platform compatibility (BSD sed doesn't support {block} syntax)
        for SUFFIX in "win32-x64.exe" "darwin-arm64.dmg" "darwin-x64.dmg" "linux-x86_64.AppImage" "linux-amd64.deb"; do
          perl -i -pe 'if (/<!-- STABLE_DOWNLOADS -->/ .. /<!-- STABLE_DOWNLOADS_END -->/) { s|Auto-Claude-[0-9.a-z-]*-'"$SUFFIX"'\]\(https://github.com/AndyMik90/Auto-Claude/releases/download/v[^/]*/Auto-Claude-[^)]*-'"$SUFFIX"'\)|Auto-Claude-'"$VERSION"'-'"$SUFFIX"'](https://github.com/AndyMik90/Auto-Claude/releases/download/v'"$VERSION"'/Auto-Claude-'"$VERSION"'-'"$SUFFIX"')|g }' README.md
        done
      fi

      rm -f README.md.bak
      git add README.md
      echo "  Updated README.md to $VERSION"
    fi

    echo "Version sync complete: $VERSION"
  fi
fi

# =============================================================================
# BACKEND CHECKS (Python) - Run first, before frontend
# =============================================================================

# Check if there are staged Python files in apps/backend
if git diff --cached --name-only | grep -q "^apps/backend/.*\.py$"; then
  echo "Python changes detected, running backend checks..."

  # Detect if we're in a worktree
  IS_WORKTREE=false
  if [ -f ".git" ]; then
    # .git is a file (not directory) in worktrees
    IS_WORKTREE=true
  fi

  # Determine ruff command (venv or global)
  RUFF=""
  if [ -f "apps/backend/.venv/bin/ruff" ]; then
    RUFF="apps/backend/.venv/bin/ruff"
  elif [ -f "apps/backend/.venv/Scripts/ruff.exe" ]; then
    RUFF="apps/backend/.venv/Scripts/ruff.exe"
  elif command -v ruff >/dev/null 2>&1; then
    RUFF="ruff"
  fi

  if [ -n "$RUFF" ]; then
    # Get only staged Python files in apps/backend (process only what's being committed)
    STAGED_PY_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep "^apps/backend/.*\.py$" || true)

    if [ -n "$STAGED_PY_FILES" ]; then
      # Run ruff linting (auto-fix) only on staged files
      echo "Running ruff lint on staged files..."
      echo "$STAGED_PY_FILES" | xargs $RUFF check --fix
      if [ $? -ne 0 ]; then
        echo "Ruff lint failed. Please fix Python linting errors before committing."
        exit 1
      fi

      # Run ruff format (auto-fix) only on staged files
      echo "Running ruff format on staged files..."
      echo "$STAGED_PY_FILES" | xargs $RUFF format

      # Re-stage only the files that were originally staged (in case ruff modified them)
      echo "$STAGED_PY_FILES" | xargs git add
    fi
  else
    if [ "$IS_WORKTREE" = true ]; then
      echo ""
      echo "⚠️  WARNING: ruff not available in this worktree."
      echo "   Python linting checks will be skipped."
      echo "   This is expected for auto-claude worktrees."
      echo "   Full validation will occur when PR is created/merged."
      echo ""
    else
      echo "Warning: ruff not found, skipping Python linting. Install with: uv pip install ruff"
    fi
  fi

  # Run pytest (skip slow/integration tests and Windows-incompatible tests for pre-commit speed)
  # Run from repo root (not apps/backend) so tests that use Path.resolve() get correct CWD.
  # PYTHONPATH includes apps/backend so imports resolve correctly.
  echo "Running Python tests..."
  (
    # Tests to skip: graphiti (external deps), merge_file_tracker/service_orchestrator/worktree/workspace (Windows path/git issues)
    # Also skip tests that require optional dependencies (pydantic structured outputs)
    # Also skip gitlab_e2e (e2e test sensitive to test-ordering env contamination, validated by CI)
    IGNORE_TESTS="--ignore=tests/test_graphiti.py --ignore=tests/test_merge_file_tracker.py --ignore=tests/test_service_orchestrator.py --ignore=tests/test_worktree.py --ignore=tests/test_workspace.py --ignore=tests/test_finding_validation.py --ignore=tests/test_sdk_structured_output.py --ignore=tests/test_structured_outputs.py --ignore=tests/test_gitlab_e2e.py"
    # Determine Python executable from venv
    VENV_PYTHON=""
    if [ -f "apps/backend/.venv/bin/python" ]; then
      VENV_PYTHON="apps/backend/.venv/bin/python"
    elif [ -f "apps/backend/.venv/Scripts/python.exe" ]; then
      VENV_PYTHON="apps/backend/.venv/Scripts/python.exe"
    fi

    # -k "not windows_path": skip tests using fake Windows paths that break
    # Path.resolve() on macOS/Linux. These are validated by CI on all platforms.
    if [ -n "$VENV_PYTHON" ]; then
      # Check if pytest is installed in venv
      if $VENV_PYTHON -c "import pytest" 2>/dev/null; then
        PYTHONPATH=apps/backend $VENV_PYTHON -m pytest tests/ -v --tb=short -x -m "not slow and not integration" -k "not windows_path" $IGNORE_TESTS
      else
        echo "Warning: pytest not installed in venv. Installing test dependencies..."
        $VENV_PYTHON -m pip install -q -r tests/requirements-test.txt
        PYTHONPATH=apps/backend $VENV_PYTHON -m pytest tests/ -v --tb=short -x -m "not slow and not integration" -k "not windows_path" $IGNORE_TESTS
      fi
    elif [ -d "apps/backend/.venv" ]; then
      echo "Warning: venv exists but Python not found in it, using system Python"
      PYTHONPATH=apps/backend python -m pytest tests/ -v --tb=short -x -m "not slow and not integration" -k "not windows_path" $IGNORE_TESTS
    elif [ "$IS_WORKTREE" = true ]; then
      echo ""
      echo "⚠️  WARNING: Python venv not available in this worktree."
      echo "   Python tests will be skipped."
      echo "   This is expected for auto-claude worktrees."
      echo "   Full validation will occur when PR is created/merged."
      echo ""
      exit 77  # GNU convention for 'test skipped' (avoids pytest exit-code collision)
    else
      echo "Warning: No .venv found in apps/backend, using system Python"
      PYTHONPATH=apps/backend python -m pytest tests/ -v --tb=short -x -m "not slow and not integration" -k "not windows_path" $IGNORE_TESTS
    fi
  )
  PYTHON_EXIT=$?
  if [ $PYTHON_EXIT -eq 77 ]; then
    echo "Backend checks passed! (Python tests skipped — worktree)"
  elif [ $PYTHON_EXIT -ne 0 ]; then
    echo "Python tests failed. Please fix failing tests before committing."
    exit 1
  else
    echo "Backend checks passed!"
  fi
fi

# =============================================================================
# FRONTEND CHECKS (TypeScript/React)
# =============================================================================

# Check if there are staged files in apps/frontend
if git diff --cached --name-only | grep -q "^apps/frontend/"; then
  echo "Frontend changes detected, running frontend checks..."

  # Detect if we're in a worktree and check if dependencies are available
  IS_WORKTREE=false
  DEPS_AVAILABLE=true

  if [ -f ".git" ]; then
    # .git is a file (not directory) in worktrees
    IS_WORKTREE=true
    echo "Detected git worktree environment"
  fi

  # Check if node_modules has actual dependencies by looking for a known package
  # @lydell/node-pty is required for terminal code and is a common source of TypeScript errors
  # It may be in root node_modules (hoisted) or apps/frontend/node_modules
  # Note: -d follows symlinks automatically, so this works for both real dirs and symlinks
  # We check for the full package path (@lydell/node-pty) rather than just the namespace
  # for precise detection - ensures the actual dependency is installed, not just any @lydell package
  if [ ! -d "node_modules/@lydell/node-pty" ] && [ ! -d "apps/frontend/node_modules/@lydell/node-pty" ]; then
    DEPS_AVAILABLE=false
  fi

  if [ "$DEPS_AVAILABLE" = false ]; then
    if [ "$IS_WORKTREE" = true ]; then
      # In worktree without dependencies - warn but allow commit
      echo ""
      echo "⚠️  WARNING: node_modules not available in this worktree."
      echo "   TypeScript and lint checks will be skipped."
      echo "   This is expected for auto-claude worktrees."
      echo "   Full validation will occur when PR is created/merged."
      echo ""
    else
      # Main repo without dependencies - this is an error
      echo "Error: node_modules not found. Run 'npm install' first."
      exit 1
    fi
  else
    # Dependencies available - run full frontend checks
    # Use subshell to isolate directory changes and prevent worktree corruption
    (
      cd apps/frontend

      # Run lint-staged (handles staged .ts/.tsx files)
      npm exec lint-staged
      if [ $? -ne 0 ]; then
        echo "lint-staged failed. Please fix linting errors before committing."
        exit 1
      fi

      # Run TypeScript type check
      echo "Running type check..."
      npm run typecheck
      if [ $? -ne 0 ]; then
        echo "Type check failed. Please fix TypeScript errors before committing."
        exit 1
      fi

      # Run linting
      echo "Running lint..."
      npm run lint
      if [ $? -ne 0 ]; then
        echo "Lint failed. Run 'npm run lint:fix' to auto-fix issues."
        exit 1
      fi

      # Check for vulnerabilities (only critical severity)
      # Note: Using critical level because electron-builder has a known high-severity
      # tar vulnerability (CVE-2026-23745) that cannot be fixed until electron-builder
      # releases an update with tar@7.x support. This is a build dependency, not runtime.
      echo "Checking for vulnerabilities..."
      npm audit --audit-level=critical
      if [ $? -ne 0 ]; then
        echo "Critical severity vulnerabilities found. Run 'npm audit fix' to resolve."
        exit 1
      fi
    )
    if [ $? -ne 0 ]; then
      exit 1
    fi
    echo "Frontend checks passed!"
  fi
fi

echo "All pre-commit checks passed!"
