#!/bin/bash
# Universal RouteRTL Project Pre-Commit Hook
# 
# This hook reads configuration from project.yml via project_manager.py
# and executes the requested checks (linting, yaml check, tests).

# 0. Source project-local hook extensions (if present)
if [ -f "hooks/pre-commit.local" ]; then
    echo "🔌 Sourcing hooks/pre-commit.local..."
    source hooks/pre-commit.local
fi

# ── Markdown-Only Detection ──
# If the commit only touches .md files, skip heavyweight checks (linting,
# regression, simulation) but still run docs-related checks (link
# validation, MkDocs build).
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACMR)
NON_MD_FILES=$(echo "$STAGED_FILES" | grep -v '\.md$' || true)
MD_ONLY=false
if [ -z "$NON_MD_FILES" ] && [ -n "$STAGED_FILES" ]; then
    MD_ONLY=true
    echo "📝 Markdown-only commit — skipping HDL/sim checks, running docs checks."
fi

# 1. Locate SDK Tools
#    Post-P2.39: sdk/ is the canonical layout (engine/, infra/, generators/, …).
#    Pre-P2.39:  tools/ held the same content (project-manager/, docs/, …).
#    Check sdk/ first so consumers that updated their submodule get the right
#    paths even if a leftover tools/ directory still exists on disk.
if [ -d "vendor/routertl/sdk" ]; then
    SDK_TOOLS="vendor/routertl/sdk"
    PROJECT_MANAGER="$SDK_TOOLS/engine/project_manager.py"
    CHECK_LINKS="$SDK_TOOLS/infra/docs/check_links.py"
elif [ -d "vendor/routertl/tools" ]; then
    # Legacy layout (pre-P2.39 consumers)
    SDK_TOOLS="vendor/routertl/tools"
    PROJECT_MANAGER="$SDK_TOOLS/project-manager/project_manager.py"
    CHECK_LINKS="$SDK_TOOLS/docs/check_links.py"
elif [ -n "$ROUTERTL_ROOT" ]; then
    SDK_TOOLS="$ROUTERTL_ROOT/sdk"
    PROJECT_MANAGER="$SDK_TOOLS/engine/project_manager.py"
    CHECK_LINKS="$SDK_TOOLS/infra/docs/check_links.py"
elif [ -d "sdk/engine" ]; then
    # Fallback for the SDK repo itself
    SDK_TOOLS="sdk"
    PROJECT_MANAGER="$SDK_TOOLS/engine/project_manager.py"
    CHECK_LINKS="$SDK_TOOLS/infra/docs/check_links.py"
elif [ -d "tools/project-manager" ]; then
    # Legacy fallback for the SDK repo itself (pre-P2.39)
    SDK_TOOLS="tools"
    PROJECT_MANAGER="$SDK_TOOLS/project-manager/project_manager.py"
    CHECK_LINKS="$SDK_TOOLS/docs/check_links.py"
else
    echo "⚠️ RouteRTL SDK tools not found. Skipping hook."
    exit 0
fi

if [ ! -f "project.yml" ]; then
    echo "⚠️ project.yml not found. Skipping hook."
    exit 0
fi

# 2. Extract Configuration
echo "🔍 Reading hook configuration from project.yml..."

# Detect Python interpreter (use venv if available)
if [ -f ".venv/bin/python3" ]; then
    PYTHON_CMD=".venv/bin/python3"
else
    PYTHON_CMD="python3"
fi

# Inject SDK repo root into PYTHONPATH so project_manager can import
# 'sdk.*' and 'routertl_core.*'.  When SDK_TOOLS is a bare name like
# "sdk" (SDK repo itself), %/* has no effect → fall back to CWD.
SDK_REPO_ROOT="${SDK_TOOLS%/*}"
if [ "$SDK_REPO_ROOT" = "$SDK_TOOLS" ]; then
    SDK_REPO_ROOT="."
fi
export PYTHONPATH="$SDK_REPO_ROOT:$PYTHONPATH"

echo "🔍 Using Python interpreter: $PYTHON_CMD"
CONFIG=$($PYTHON_CMD "$PROJECT_MANAGER" project.yml --gen-hook-config)

if [ $? -ne 0 ]; then
    echo "❌ Failed to parse project.yml. Commit aborted."
    exit 1
fi

eval "$CONFIG"

# 3. Check Enabled Status
if [ "$HOOK_ENABLED" != "true" ]; then
    echo "⏩ Hooks disabled in project.yml. Skipping."
    exit 0
fi

# 3.5. Frozen Directory Guard
if [ -n "$HOOK_FROZEN_DIRS" ]; then
    STAGED_FILES=$(git diff --cached --name-only)
    for dir in $HOOK_FROZEN_DIRS; do
        VIOLATIONS=$(echo "$STAGED_FILES" | grep "^${dir}/" || true)
        if [ -n "$VIOLATIONS" ]; then
            echo "❌ Frozen directory violation: '$dir' is marked frozen in project.yml"
            echo "   Offending files:"
            echo "$VIOLATIONS" | sed 's/^/     /'
            echo ""
            echo "   Remove these files from staging (git reset HEAD <file>) or update project.yml."
            exit 1
        fi
    done
    echo "✅ Frozen directory check passed."
fi

# 4. Phase 1.5: Markdown Link Validation
if [ "$HOOK_CHECK_LINKS" = "true" ]; then
    echo "🔗 Validating Markdown Links..."
    EXCLUDE_ARGS=""
    for dir in $HOOK_EXCLUDE_DOC_DIRS; do
        EXCLUDE_ARGS="$EXCLUDE_ARGS --exclude $dir"
    done
    $PYTHON_CMD "$CHECK_LINKS" --dir docs $EXCLUDE_ARGS
    if [ $? -ne 0 ]; then
        echo "❌ Markdown link validation failed. Commit aborted."
        exit 1
    fi
fi

# 4.5 MkDocs Documentation Build (strict mode)
if [ "$HOOK_CHECK_DOCS" = "true" ] && [ -f "mkdocs.yml" ]; then
    echo "📚 Building documentation (mkdocs build --strict)..."
    MKDOCS_TMPDIR="/tmp/mkdocs-precommit-$$"
    mkdocs build --strict --site-dir "$MKDOCS_TMPDIR" 2>&1
    if [ $? -ne 0 ]; then
        echo "❌ MkDocs build failed. Commit aborted."
        rm -rf "$MKDOCS_TMPDIR"
        exit 1
    fi
    rm -rf "$MKDOCS_TMPDIR"
    echo "✅ Documentation build passed."
fi

# 4. Check YAML (implicit in the parsing above, but good to be explicit)
if [ "$HOOK_CHECK_YAML" = "true" ]; then
    echo "✅ YAML check passed (implicit)."
fi

# 4.7 Python Linting (ruff)
if [ "$HOOK_LINT_PYTHON" = "true" ] && [ "$MD_ONLY" = "false" ]; then
    echo "🐍 Running Python linting (ruff check)..."
    ruff check .
    if [ $? -ne 0 ]; then
        echo "❌ Python linting failed. Commit aborted."
        exit 1
    fi
    echo "✅ Python linting passed."
fi

# 5. Run Linting
if [ "$HOOK_LINT" = "true" ] && [ "$MD_ONLY" = "false" ]; then
    echo "🧹 Running HDL Linting..."
    rm -f sim/lint.status
    make linting HOOK_EXCLUDE_LINT="$HOOK_EXCLUDE_LINT"
    
    # Check status file
    if [ ! -f "sim/lint.status" ]; then
         echo "❌ Linting tool execution failed (No status file)."
         exit 1
    fi
    
    LINT_STATUS=$(cat sim/lint.status)
    if [ "$LINT_STATUS" != "0" ]; then
        echo "❌ Linting failed. Commit aborted."
        exit 1
    fi
fi

# 5.5 Run Regression (if enabled)
if [ "$HOOK_RUN_REGRESSION" = "true" ] && [ "$MD_ONLY" = "false" ]; then
    echo "🧪 Running full regression suite (make regression)..."
    make regression
    if [ $? -ne 0 ]; then
        echo "❌ Regression failed. Commit aborted."
        exit 1
    fi
fi

# 6. Run Selected Tests
if [ -n "$HOOK_TESTS" ] && [ "$MD_ONLY" = "false" ]; then
    echo "🧪 Running configured tests: $HOOK_TESTS"
    
    # Clean simulation workspace to avoid false positives from stale artifacts
    echo "🧹 Cleaning simulation workspace..."
    make clean
    # Regenerate build_env.mk (destroyed by make clean) so regression
    # tests that depend on it don't fail with FileNotFoundError.
    if [ -f "project.yml" ]; then
        $PYTHON_CMD "$PROJECT_MANAGER" project.yml --out-mk build_env.mk 2>/dev/null && \
            echo "✅ Regenerated build_env.mk after clean." || true
    fi
    
    COLLECTED_PATTERNS=""
    for test in $HOOK_TESTS; do
        # Check if test is in the exclusion list
        SKIP_TEST=false
        for excluded in $HOOK_EXCLUDE_TESTS; do
            if [ "$test" = "$excluded" ]; then
                echo "   ⏭️  Skipping (excluded): $test"
                SKIP_TEST=true
                break
            fi
        done
        
        if [ "$SKIP_TEST" = "false" ]; then
            COLLECTED_PATTERNS="$COLLECTED_PATTERNS --pattern ${test}.py"
        fi
    done

    if [ -n "$COLLECTED_PATTERNS" ]; then
        echo "   ▶ Running consolidated simulation suite..."
        make simulation SIM_EXTRA_ARGS="$COLLECTED_PATTERNS"
        if [ $? -ne 0 ]; then
            echo "❌ Regression failed. Commit aborted."
            exit 1
        fi
    fi
fi

# ── Re-stage files modified by this hook ──
# The pre-commit hook runs `make clean` (destroys build_env.mk), then
# regenerates it via project_manager.py, and produces a new
# regression_summary.txt from simulation. This creates a staged vs
# working-tree mismatch (git shows `MM`) that silently prevents commit.
# Fix: re-add any tracked files the hook itself modified.
RESTAGE_FILES="build_env.mk hw/sim/logs/regression_summary.txt"
for f in $RESTAGE_FILES; do
    if [ -f "$f" ] && git ls-files --error-unmatch "$f" >/dev/null 2>&1; then
        git add "$f"
    fi
done

echo "✅ All checks passed."
exit 0
