#!/usr/bin/env bash
#
# Tests for Codex-native hook installation and merge behavior.
#

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
source "$SCRIPT_DIR/test-helpers.sh"

INSTALL_SCRIPT="$PROJECT_ROOT/scripts/install-skill.sh"

echo "=========================================="
echo "Codex Hook Install Tests"
echo "=========================================="
echo ""

if [[ ! -x "$INSTALL_SCRIPT" ]]; then
    echo "FATAL: install-skill.sh not found at $INSTALL_SCRIPT" >&2
    exit 1
fi

if ! command -v python3 >/dev/null 2>&1; then
    echo "FATAL: python3 is required for this test" >&2
    exit 1
fi

setup_test_dir

FAKE_BIN="$TEST_DIR/bin"
CODEX_HOME_DIR="$TEST_DIR/codex-home"
HOOKS_FILE="$CODEX_HOME_DIR/hooks.json"
FEATURE_LOG="$TEST_DIR/codex-features.log"
XDG_CONFIG_HOME_DIR="$TEST_DIR/xdg-config"
HUMANIZE_USER_CONFIG="$XDG_CONFIG_HOME_DIR/humanize/config.json"
COMMAND_BIN_DIR="$TEST_DIR/command-bin"
mkdir -p "$FAKE_BIN" "$CODEX_HOME_DIR" "$COMMAND_BIN_DIR"

cat > "$FAKE_BIN/codex" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail

if [[ "${1:-}" == "features" && "${2:-}" == "list" ]]; then
    cat <<'LIST'
hooks                            stable             false
LIST
    exit 0
fi

if [[ "${1:-}" == "features" && "${2:-}" == "enable" && "${3:-}" == "hooks" ]]; then
    printf 'CODEX_HOME=%s\n' "${CODEX_HOME:-}" >> "${TEST_CODEX_FEATURE_LOG:?}"
    mkdir -p "${CODEX_HOME:?}"
    : > "${CODEX_HOME}/.hooks-enabled"
    exit 0
fi

if [[ "${1:-}" == "exec" ]]; then
    cat <<'OUT'
LESSON_IDS: NONE
RATIONALE: No matching lessons found (fake codex exec).
OUT
    exit 0
fi

echo "unexpected fake codex invocation: $*" >&2
exit 1
EOF
chmod +x "$FAKE_BIN/codex"

cat > "$HOOKS_FILE" <<'EOF'
{
  "description": "Existing hooks",
  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "/custom/session-start.sh",
            "timeout": 15
          }
        ]
      }
    ],
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "/tmp/old/skills/humanize/hooks/loop-codex-stop-hook.sh",
            "timeout": 30
          }
        ]
      },
      {
        "hooks": [
          {
            "type": "command",
            "command": "/custom/keep-me.sh",
            "timeout": 5
          }
        ]
      }
    ]
  }
}
EOF

PATH="$FAKE_BIN:$PATH" TEST_CODEX_FEATURE_LOG="$FEATURE_LOG" XDG_CONFIG_HOME="$XDG_CONFIG_HOME_DIR" \
    "$INSTALL_SCRIPT" \
    --target codex \
    --codex-config-dir "$CODEX_HOME_DIR" \
    --codex-skills-dir "$CODEX_HOME_DIR/skills" \
    --command-bin-dir "$COMMAND_BIN_DIR" \
    > "$TEST_DIR/install.log" 2>&1

if [[ -f "$CODEX_HOME_DIR/skills/humanize/SKILL.md" ]]; then
    pass "Codex install syncs Humanize skill bundle"
else
    fail "Codex install syncs Humanize skill bundle" "skills/humanize/SKILL.md exists" "missing"
fi

if [[ -f "$CODEX_HOME_DIR/skills/humanize-rlcr/SKILL.md" ]]; then
    pass "Codex install keeps humanize-rlcr entrypoint skill"
else
    fail "Codex install keeps humanize-rlcr entrypoint skill" "skills/humanize-rlcr/SKILL.md exists" "missing"
fi

if [[ -f "$HOOKS_FILE" ]]; then
    pass "Codex install writes hooks.json"
else
    fail "Codex install writes hooks.json" "$HOOKS_FILE exists" "missing"
fi

if [[ -f "$CODEX_HOME_DIR/.hooks-enabled" ]]; then
    pass "Codex install enables hooks feature"
else
    fail "Codex install enables hooks feature" ".hooks-enabled marker exists" "missing"
fi

if [[ -f "$HUMANIZE_USER_CONFIG" ]]; then
    pass "Codex install writes Humanize user config"
else
    fail "Codex install writes Humanize user config" "$HUMANIZE_USER_CONFIG exists" "missing"
fi

if [[ -x "$COMMAND_BIN_DIR/bitlesson-selector" ]]; then
    pass "Codex install writes a PATH-ready bitlesson-selector shim"
else
    fail "Codex install writes a PATH-ready bitlesson-selector shim" "$COMMAND_BIN_DIR/bitlesson-selector exists" "missing"
fi

if [[ "$(jq -r '.bitlesson_model // empty' "$HUMANIZE_USER_CONFIG")" == "gpt-5.5" ]]; then
    pass "Codex install seeds bitlesson_model with a Codex/OpenAI model"
else
    fail "Codex install seeds bitlesson_model with a Codex/OpenAI model" \
        "gpt-5.5" "$(jq -c '.' "$HUMANIZE_USER_CONFIG" 2>/dev/null || echo MISSING)"
fi

if [[ "$(jq -r '.provider_mode // empty' "$HUMANIZE_USER_CONFIG")" == "codex-only" ]]; then
    pass "Codex install marks Humanize user config as codex-only"
else
    fail "Codex install marks Humanize user config as codex-only" \
        "codex-only" "$(jq -c '.' "$HUMANIZE_USER_CONFIG" 2>/dev/null || echo MISSING)"
fi

runtime_root="$CODEX_HOME_DIR/skills/humanize"
PY_OUTPUT="$(
    python3 - "$HOOKS_FILE" "$runtime_root" <<'PY'
import json
import pathlib
import sys

hooks_file = pathlib.Path(sys.argv[1])
runtime_root = sys.argv[2]
data = json.loads(hooks_file.read_text(encoding="utf-8"))

commands = []
for group in data["hooks"]["Stop"]:
    for hook in group.get("hooks", []):
        command = hook.get("command")
        if isinstance(command, str):
            commands.append(command)

expected = {
    f"{runtime_root}/hooks/loop-codex-stop-hook.sh",
}

print("FOUND=" + ("1" if expected.issubset(set(commands)) else "0"))
print("KEEP=" + ("1" if "/custom/keep-me.sh" in commands else "0"))
print("OLD=" + ("1" if any("/tmp/old/skills/humanize/hooks/" in cmd for cmd in commands) else "0"))
print("SESSION=" + ("1" if data["hooks"]["SessionStart"][0]["hooks"][0]["command"] == "/custom/session-start.sh" else "0"))
print("COUNT=" + str(sum(1 for cmd in commands if "/humanize/hooks/" in cmd)))
PY
)"

if grep -q '^FOUND=1$' <<<"$PY_OUTPUT"; then
    pass "Codex install adds managed Humanize Stop hook commands"
else
    fail "Codex install adds managed Humanize Stop hook commands" "FOUND=1" "$PY_OUTPUT"
fi

if grep -q '^KEEP=1$' <<<"$PY_OUTPUT"; then
    pass "Codex install preserves unrelated Stop hooks"
else
    fail "Codex install preserves unrelated Stop hooks" "KEEP=1" "$PY_OUTPUT"
fi

if grep -q '^OLD=0$' <<<"$PY_OUTPUT"; then
    pass "Codex install removes stale Humanize hook commands"
else
    fail "Codex install removes stale Humanize hook commands" "OLD=0" "$PY_OUTPUT"
fi

if grep -q '^SESSION=1$' <<<"$PY_OUTPUT"; then
    pass "Codex install preserves SessionStart hooks"
else
    fail "Codex install preserves SessionStart hooks" "SESSION=1" "$PY_OUTPUT"
fi

if grep -q '^COUNT=1$' <<<"$PY_OUTPUT"; then
    pass "Codex install writes exactly one managed Humanize Stop hook"
else
    fail "Codex install writes exactly one managed Humanize Stop hook" "COUNT=1" "$PY_OUTPUT"
fi

mkdir -p "$TEST_DIR/project"
cat > "$TEST_DIR/project/bitlesson.md" <<'EOF'
# BitLesson Knowledge Base
## Entries
<!-- placeholder -->
EOF

shim_output="$(
    CLAUDE_PROJECT_DIR="$TEST_DIR/project" \
    XDG_CONFIG_HOME="$XDG_CONFIG_HOME_DIR" \
    PATH="$COMMAND_BIN_DIR:$FAKE_BIN:$PATH" \
    "$COMMAND_BIN_DIR/bitlesson-selector" \
    --task "Verify the shim dispatches into the installed runtime" \
    --paths "README.md" \
    --bitlesson-file "$TEST_DIR/project/bitlesson.md"
)"

if grep -q '^LESSON_IDS: NONE$' <<<"$shim_output"; then
    pass "bitlesson-selector shim dispatches into installed runtime"
else
    fail "bitlesson-selector shim dispatches into installed runtime" "LESSON_IDS: NONE" "$shim_output"
fi

PATH="$FAKE_BIN:$PATH" TEST_CODEX_FEATURE_LOG="$FEATURE_LOG" XDG_CONFIG_HOME="$XDG_CONFIG_HOME_DIR" \
    "$INSTALL_SCRIPT" \
    --target codex \
    --codex-config-dir "$CODEX_HOME_DIR" \
    --codex-skills-dir "$CODEX_HOME_DIR/skills" \
    > "$TEST_DIR/install-2.log" 2>&1

PY_OUTPUT_2="$(
    python3 - "$HOOKS_FILE" <<'PY'
import json
import pathlib
import sys

hooks_file = pathlib.Path(sys.argv[1])
data = json.loads(hooks_file.read_text(encoding="utf-8"))

commands = []
for group in data["hooks"]["Stop"]:
    for hook in group.get("hooks", []):
        command = hook.get("command")
        if isinstance(command, str):
            commands.append(command)

print(sum(1 for cmd in commands if "/humanize/hooks/" in cmd))
PY
)"

if [[ "$PY_OUTPUT_2" == "1" ]]; then
    pass "Codex install is idempotent for managed hook commands"
else
    fail "Codex install is idempotent for managed hook commands" "1" "$PY_OUTPUT_2"
fi

if [[ "$(wc -l < "$FEATURE_LOG" | tr -d ' ')" == "2" ]]; then
    pass "Codex feature enable runs on each Codex install/update"
else
    fail "Codex feature enable runs on each Codex install/update" "2 log entries" "$(cat "$FEATURE_LOG")"
fi

LEGACY_CONFIG_HOME="$TEST_DIR/codex-home-legacy-config"
mkdir -p "$LEGACY_CONFIG_HOME"
cat > "$LEGACY_CONFIG_HOME/config.toml" <<'EOF'
[features]
codex_hooks = true
EOF

set +e
PATH="$FAKE_BIN:$PATH" TEST_CODEX_FEATURE_LOG="$FEATURE_LOG" \
    "$INSTALL_SCRIPT" \
    --target codex \
    --codex-config-dir "$LEGACY_CONFIG_HOME" \
    --codex-skills-dir "$LEGACY_CONFIG_HOME/skills" \
    > "$TEST_DIR/install-legacy-config.log" 2>&1
LEGACY_CONFIG_EXIT=$?
set -e

if [[ "$LEGACY_CONFIG_EXIT" -ne 0 ]]; then
    pass "Codex install rejects legacy codex_hooks config"
else
    fail "Codex install rejects legacy codex_hooks config" "non-zero exit" "exit 0"
fi

if grep -q "legacy feature key 'codex_hooks'" "$TEST_DIR/install-legacy-config.log" \
    && grep -q "hooks = true" "$TEST_DIR/install-legacy-config.log"; then
    pass "Legacy codex_hooks config failure explains hooks rename"
else
    fail "Legacy codex_hooks config failure explains hooks rename" \
        "error mentioning legacy codex_hooks and hooks = true" \
        "$(cat "$TEST_DIR/install-legacy-config.log")"
fi

LEGACY_ONLY_BIN="$TEST_DIR/bin-legacy-only"
LEGACY_ONLY_HOME="$TEST_DIR/codex-home-legacy-only"
mkdir -p "$LEGACY_ONLY_BIN" "$LEGACY_ONLY_HOME"

cat > "$LEGACY_ONLY_BIN/codex" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail

if [[ "${1:-}" == "features" && "${2:-}" == "list" ]]; then
    cat <<'LIST'
codex_hooks                      under development  false
LIST
    exit 0
fi

echo "unexpected fake codex invocation: $*" >&2
exit 1
EOF
chmod +x "$LEGACY_ONLY_BIN/codex"

set +e
PATH="$LEGACY_ONLY_BIN:$PATH" \
    "$INSTALL_SCRIPT" \
    --target codex \
    --codex-config-dir "$LEGACY_ONLY_HOME" \
    --codex-skills-dir "$LEGACY_ONLY_HOME/skills" \
    > "$TEST_DIR/install-legacy-only.log" 2>&1
LEGACY_ONLY_EXIT=$?
set -e

if [[ "$LEGACY_ONLY_EXIT" -ne 0 ]]; then
    pass "Codex install rejects Codex builds exposing only legacy codex_hooks"
else
    fail "Codex install rejects Codex builds exposing only legacy codex_hooks" "non-zero exit" "exit 0"
fi

if grep -q "legacy 'codex_hooks' feature" "$TEST_DIR/install-legacy-only.log" \
    && grep -q "Upgrade Codex" "$TEST_DIR/install-legacy-only.log"; then
    pass "Legacy-only feature failure asks user to upgrade Codex"
else
    fail "Legacy-only feature failure asks user to upgrade Codex" \
        "error mentioning legacy codex_hooks and Upgrade Codex" \
        "$(cat "$TEST_DIR/install-legacy-only.log")"
fi

UNSUPPORTED_BIN="$TEST_DIR/bin-unsupported"
UNSUPPORTED_HOME="$TEST_DIR/codex-home-unsupported"
mkdir -p "$UNSUPPORTED_BIN" "$UNSUPPORTED_HOME"

cat > "$UNSUPPORTED_BIN/codex" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail

if [[ "${1:-}" == "features" && "${2:-}" == "list" ]]; then
    cat <<'LIST'
apply_patch_freeform             under development  false
LIST
    exit 0
fi

echo "unexpected fake codex invocation: $*" >&2
exit 1
EOF
chmod +x "$UNSUPPORTED_BIN/codex"

set +e
PATH="$UNSUPPORTED_BIN:$PATH" \
    "$INSTALL_SCRIPT" \
    --target codex \
    --codex-config-dir "$UNSUPPORTED_HOME" \
    --codex-skills-dir "$UNSUPPORTED_HOME/skills" \
    > "$TEST_DIR/install-unsupported.log" 2>&1
UNSUPPORTED_EXIT=$?
set -e

if [[ "$UNSUPPORTED_EXIT" -ne 0 ]]; then
    pass "Codex install rejects builds without native hooks support"
else
    fail "Codex install rejects builds without native hooks support" "non-zero exit" "exit 0"
fi

if grep -q "native 'hooks' feature" "$TEST_DIR/install-unsupported.log" \
    && grep -q "Upgrade Codex" "$TEST_DIR/install-unsupported.log"; then
    pass "Unsupported Codex failure explains missing hooks feature"
else
    fail "Unsupported Codex failure explains missing hooks feature" \
        "error mentioning native hooks feature and Upgrade Codex" \
        "$(cat "$TEST_DIR/install-unsupported.log")"
fi

print_test_summary "Codex Hook Install Tests"
