#!/bin/bash
# Pre-commit hook for Atmosphere Framework
# Checks copyright headers on Java source files and blocks suspicious files

set -e

# Check for files with suspicious patterns (backups, old files, etc.)
check_suspicious_files() {
    local suspicious_files=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(bak|orig|tmp|swp)$|_old\.|old_|\.old\.' || true)

    if [ -n "$suspicious_files" ]; then
        echo "ERROR: Commit blocked - Found suspicious files:"
        echo "$suspicious_files" | sed 's/^/  - /'
        echo ""
        echo "These files appear to be backups or old versions."
        echo "Please remove them or rename them before committing."
        return 1
    fi
    return 0
}

# Check for Apache 2.0 copyright headers in Java source files
check_copyright_headers() {
    local missing_headers=""

    # Get staged Java files (added or modified) in src/ directories
    local java_files=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.java$' | grep -v '/target/' || true)

    for file in $java_files; do
        if [ -f "$file" ] && ! grep -q "Copyright 2008-20[0-9][0-9] Async-IO.org" "$file" 2>/dev/null; then
            missing_headers="$missing_headers\n  - $file"
        fi
    done

    if [ -n "$missing_headers" ]; then
        echo "ERROR: Commit blocked - Missing copyright headers:"
        echo -e "$missing_headers"
        echo ""
        echo "All Java source files must have the Atmosphere copyright header:"
        echo "  /*"
        echo "   * Copyright 2008-2026 Async-IO.org"
        echo "   *"
        echo "   * Licensed under the Apache License, Version 2.0 ..."
        echo "   */"
        echo ""
        echo "Please add the header to the listed files."
        return 1
    fi
    return 0
}

# Check for unused imports in staged Java files
check_unused_imports() {
    local java_files=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.java$' | grep -v '/target/' || true)
    local has_warnings=false

    for file in $java_files; do
        if [ ! -f "$file" ]; then
            continue
        fi

        # Check for duplicate imports
        local dup_imports=$(grep '^import ' "$file" | sort | uniq -d)
        if [ -n "$dup_imports" ]; then
            echo "WARNING: Duplicate imports in $file:"
            echo "$dup_imports" | sed 's/^/  /'
            has_warnings=true
        fi

        # Check for unused imports (non-wildcard, non-static)
        while IFS= read -r import_line; do
            # Extract the class name (last component of the import)
            local class_name=$(echo "$import_line" | sed 's/import \(static \)\?//;s/;$//' | awk -F. '{print $NF}')
            # Skip wildcard imports
            if [ "$class_name" = "*" ]; then
                continue
            fi
            # Count occurrences outside import/package lines
            local usage_count=$(grep -v '^\s*import ' "$file" | grep -v '^\s*package ' | grep -c "\b${class_name}\b" 2>/dev/null || true)
            if [ "$usage_count" -eq 0 ]; then
                echo "WARNING: Unused import in $file: $import_line"
                has_warnings=true
            fi
        done < <(grep '^import [^s]' "$file" | grep -v '\.\*;$')
    done

    if [ "$has_warnings" = true ]; then
        echo ""
        echo "ERROR: Commit blocked - Java warnings detected."
        echo "Please fix the warnings listed above before committing."
        return 1
    fi
    return 0
}

# Compile changed modules to catch javac warnings (-Werror).
# Escape hatch for sandboxed environments where Maven Central is
# unreachable (CI runners, cloud coding sandboxes, disconnected envs).
# Two signals are required — explicit intent (ATMOSPHERE_OFFLINE_COMMIT=1)
# AND one of the recognised sandbox markers (CI, GITHUB_ACTIONS,
# CODESPACES, CLAUDE_CODE_SANDBOX, ATMOSPHERE_SANDBOX). On a normal dev
# machine the bypass stays inert.
check_compile_warnings() {
    if [ -n "$ATMOSPHERE_OFFLINE_COMMIT" ]; then
        if [ -z "$CI" ] && [ -z "$GITHUB_ACTIONS" ] && [ -z "$CODESPACES" ] \
                && [ -z "$CLAUDE_CODE_SANDBOX" ] && [ -z "$ATMOSPHERE_SANDBOX" ]; then
            echo "ERROR: ATMOSPHERE_OFFLINE_COMMIT ignored — not in a recognised sandbox." >&2
            echo "       Set one of CI, GITHUB_ACTIONS, CODESPACES," >&2
            echo "       CLAUDE_CODE_SANDBOX, or ATMOSPHERE_SANDBOX to activate." >&2
            return 1
        fi
        echo "INFO: ATMOSPHERE_OFFLINE_COMMIT honoured (sandbox detected) —"
        echo "      skipping 'mvnw compile' check. Verify -Werror locally."
        return 0
    fi

    local java_files=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.java$' | grep -v '/target/' || true)

    if [ -z "$java_files" ]; then
        return 0
    fi

    # Extract unique Maven module paths from staged Java files
    local modules=""
    for file in $java_files; do
        local module=""
        if [[ "$file" == modules/* ]]; then
            # e.g. modules/cpr/src/... -> modules/cpr
            module=$(echo "$file" | cut -d/ -f1-2)
        elif [[ "$file" == samples/* ]]; then
            # e.g. samples/spring-boot-chat/src/... -> samples/spring-boot-chat
            module=$(echo "$file" | cut -d/ -f1-2)
        fi
        if [ -n "$module" ] && [ -f "$module/pom.xml" ]; then
            modules="$modules $module"
        fi
    done

    # Deduplicate and join with commas (strip leading/trailing whitespace first)
    modules=$(echo "$modules" | tr ' ' '\n' | sed '/^$/d' | sort -u | tr '\n' ',' | sed 's/,$//')

    if [ -z "$modules" ]; then
        return 0
    fi

    # Profile-gated modules need special handling: they are not part of
    # the default reactor and would cause "Could not find the selected
    # project" errors. Compile them with their profile, then remove them
    # from the standard compile set.
    local profile_modules=""
    local standard_modules=""
    for mod in $(echo "$modules" | tr ',' '\n'); do
        case "$mod" in
            modules/benchmarks) profile_modules="$profile_modules $mod" ;;
            *)                  standard_modules="$standard_modules $mod" ;;
        esac
    done
    standard_modules=$(echo "$standard_modules" | tr ' ' '\n' | sed '/^$/d' | tr '\n' ',' | sed 's/,$//')
    profile_modules=$(echo "$profile_modules" | tr ' ' '\n' | sed '/^$/d' | tr '\n' ',' | sed 's/,$//')

    # Compile profile-gated modules with their profile
    if [ -n "$profile_modules" ]; then
        echo "Compiling profile-gated modules: $profile_modules (-Pperf)"
        if ! ./mvnw compile test-compile -Pperf -pl "$profile_modules" -am -DskipTests -q 2>&1; then
            echo ""
            echo "ERROR: Profile-gated module compilation failed."
            return 1
        fi
    fi

    if [ -z "$standard_modules" ]; then
        return 0
    fi
    modules="$standard_modules"

    echo "Compiling changed modules: $modules"
    if ! ./mvnw clean compile test-compile -pl "$modules" -DskipTests -q 2>&1; then
        echo ""
        echo "ERROR: Commit blocked — compilation failed (warnings or errors)."
        echo "Run './mvnw compile -pl $modules' to see details."
        return 1
    fi
    return 0
}

# Run architectural validation — full matrix. The script was previously
# invoked with --fast; that flag was removed (2026-04-20) so the
# extended checks (Test Integrity, Dead Code Patterns, etc.) run on
# every commit. The full run is still seconds of ripgrep, not minutes.
check_architectural_validation() {
    local script="$(git rev-parse --show-toplevel)/scripts/architectural-validation.sh"
    if [ -x "$script" ]; then
        if ! "$script"; then
            echo ""
            echo "ERROR: Commit blocked — architectural validation failed."
            return 1
        fi
    fi
    return 0
}

# Main execution
main() {
    local checks_passed=true

    if ! check_suspicious_files; then
        checks_passed=false
    fi

    if ! check_copyright_headers; then
        checks_passed=false
    fi

    if ! check_unused_imports; then
        checks_passed=false
    fi

    if ! check_architectural_validation; then
        checks_passed=false
    fi

    if ! check_compile_warnings; then
        checks_passed=false
    fi

    if [ "$checks_passed" = false ]; then
        exit 1
    fi

    echo "All pre-commit checks passed"
    exit 0
}

main "$@"
