#!/usr/bin/env bash
set -e

# Pre-commit Hook
#
# To install:
#   git config core.hooksPath .githooks
#
# To bypass (use sparingly):
#   git commit --no-verify

RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m'

echo "Running pre-commit checks..."

if [[ -n "${TMPDIR:-}" && ! -d "$TMPDIR" ]]; then
    export TMPDIR=/tmp
fi

workspace_package_names() {
    cargo metadata --no-deps --format-version 1 2>/dev/null |
        python -c 'import json,sys; data=json.load(sys.stdin); [print(pkg["name"]) for pkg in data.get("packages", [])]'
}

# 0. Prevent committing gitignored files
echo -n "Checking for gitignored files... "
ignored_staged=$(git diff --cached --name-only --diff-filter=d | while read -r file; do
  if git check-ignore -q "$file" 2>/dev/null; then
    echo "$file"
  fi
done)

if [[ -n "${ignored_staged}" ]]; then
    echo -e "${RED}FAILED${NC}"
    echo "error: gitignored files must not be included in source control:" >&2
    echo "${ignored_staged}" | sed 's/^/  /' >&2
    echo "" >&2
    echo "Remove them with: git reset HEAD <file>" >&2
    exit 1
fi
echo -e "${GREEN}OK${NC}"

# 0.5. Simulator-only staged path: run targeted subsystem checks and skip the
# broader staged-crate fallback path so unrelated workspace breakage does not
# block simulator-only work.
if ./scripts/check/simulator-subsystem.sh --applies-to-staged >/dev/null 2>&1; then
    echo -n "Checking simulator subsystem... "
    if just check-simulator-subsystem-staged >/dev/null; then
        echo -e "${GREEN}OK${NC}"
    else
        echo -e "${RED}FAILED${NC}"
        exit 1
    fi

    empty_dirs=$(find . -type d -empty -not -path './.git/*' -not -path '*/target/*' -not -path '*/node_modules/*' -not -path '*/.lake/*' 2>/dev/null)
    if [[ -n "$empty_dirs" ]]; then
        echo "Removing empty directories:"
        echo "$empty_dirs" | while read -r d; do
            echo "  $d"
            rmdir "$d"
        done
    fi

    echo -e "${GREEN}Pre-commit checks passed!${NC}"
    echo ""
    echo "Tip: Run './scripts/lint-check.sh' for comprehensive style guide checks"
    exit 0
fi

# 1. Format check (only crates with staged .rs files)
echo -n "Checking formatting... "
staged_rs=$(git diff --cached --name-only --diff-filter=d | grep '\.rs$' || true)
if [[ -z "$staged_rs" ]]; then
    echo -e "${GREEN}OK${NC} (no Rust files staged)"
else
    workspace_packages="$(workspace_package_names)"
    fmt_targets=()
    seen_fmt=""
    while IFS= read -r rs_file; do
        [[ -z "$rs_file" ]] && continue
        crate_dir="$rs_file"
        while [[ "$crate_dir" != "." ]]; do
            crate_dir="$(dirname "$crate_dir")"
            if [[ -f "$crate_dir/Cargo.toml" ]]; then
                crate_name=$(grep -m1 '^name' "$crate_dir/Cargo.toml" | sed 's/.*= *"//;s/".*//')
                target_key="$crate_dir/Cargo.toml"
                if [[ -n "$crate_name" && "\n$workspace_packages\n" == *$'\n'"$crate_name"$'\n'* ]]; then
                    target_key="workspace:$crate_name"
                    target_cmd=(cargo fmt -p "$crate_name" -- --check)
                else
                    target_cmd=(cargo fmt --manifest-path "$crate_dir/Cargo.toml" -- --check)
                fi
                if [[ ! " $seen_fmt " =~ " $target_key " ]]; then
                    fmt_targets+=("${target_cmd[*]}")
                    seen_fmt="$seen_fmt $target_key"
                fi
                break
            fi
        done
    done <<< "$staged_rs"

    if [[ ${#fmt_targets[@]} -eq 0 ]]; then
        echo -e "${GREEN}OK${NC} (no crates affected)"
    else
        fmt_failed=0
        for fmt_cmd in "${fmt_targets[@]}"; do
            if ! eval "$fmt_cmd" >/dev/null 2>&1; then
                fmt_failed=1
                break
            fi
        done
        if [[ $fmt_failed -eq 0 ]]; then
            echo -e "${GREEN}OK${NC}"
        else
            echo -e "${RED}FAILED${NC}"
            echo "Run 'cargo fmt --all' to fix formatting"
            exit 1
        fi
    fi
fi

# 2. Quick compile check (only crates with staged changes)
echo -n "Checking compilation... "
if [[ -z "$staged_rs" ]]; then
    echo -e "${GREEN}OK${NC} (no Rust files staged)"
else
    workspace_packages="$(workspace_package_names)"
    check_targets=()
    seen_crates=""
    while IFS= read -r rs_file; do
        [[ -z "$rs_file" ]] && continue
        crate_dir="$rs_file"
        while [[ "$crate_dir" != "." ]]; do
            crate_dir="$(dirname "$crate_dir")"
            if [[ -f "$crate_dir/Cargo.toml" ]]; then
                crate_name=$(grep -m1 '^name' "$crate_dir/Cargo.toml" | sed 's/.*= *"//;s/".*//')
                target_key="$crate_dir/Cargo.toml"
                if [[ -n "$crate_name" && "\n$workspace_packages\n" == *$'\n'"$crate_name"$'\n'* ]]; then
                    target_key="workspace:$crate_name"
                    target_cmd=(cargo check -p "$crate_name" --all-targets --all-features)
                else
                    target_cmd=(cargo check --manifest-path "$crate_dir/Cargo.toml" --all-targets --all-features)
                fi
                if [[ ! " $seen_crates " =~ " $target_key " ]]; then
                    check_targets+=("${target_cmd[*]}")
                    seen_crates="$seen_crates $target_key"
                fi
                break
            fi
        done
    done <<< "$staged_rs"

    if [[ ${#check_targets[@]} -eq 0 ]]; then
        echo -e "${GREEN}OK${NC} (no crates affected)"
    else
        check_failed=0
        for check_cmd in "${check_targets[@]}"; do
            if ! eval "$check_cmd" >/dev/null 2>&1; then
                check_failed=1
                break
            fi
        done
        if [[ $check_failed -eq 0 ]]; then
            echo -e "${GREEN}OK${NC}"
        else
            echo -e "${RED}FAILED${NC}"
            exit 1
        fi
    fi
fi

# 3. Remove empty directories
empty_dirs=$(find . -type d -empty -not -path './.git/*' -not -path '*/target/*' -not -path '*/node_modules/*' -not -path '*/.lake/*' 2>/dev/null)
if [[ -n "$empty_dirs" ]]; then
    echo "Removing empty directories:"
    echo "$empty_dirs" | while read -r d; do
        echo "  $d"
        rmdir "$d"
    done
fi

echo -e "${GREEN}Pre-commit checks passed!${NC}"
echo ""
echo "Tip: Run './scripts/lint-check.sh' for comprehensive style guide checks"
