#!/usr/bin/env bash

set -euo pipefail

ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
SESSION_START_HOOK="$ROOT_DIR/hooks/okf-session-start.sh"
SYNC_HOOK="$ROOT_DIR/hooks/okf-sync.sh"

fail() {
  printf 'FAIL: %s\n' "$1" >&2
  exit 1
}

assert_eq() {
  local actual="$1"
  local expected="$2"
  local message="$3"
  [[ "$actual" == "$expected" ]] || fail "$message (expected '$expected', got '$actual')"
}

assert_contains() {
  local haystack="$1"
  local needle="$2"
  local message="$3"
  [[ "$haystack" == *"$needle"* ]] || fail "$message (missing '$needle')"
}

make_fixture() {
  local tmpdir
  tmpdir="$(mktemp -d)"
  mkdir -p "$tmpdir/repo/.git" "$tmpdir/repo/bin"
  printf '%s\n' "$tmpdir"
}

write_fake_okf() {
  local repo_root="$1"
  local exit_code="${2:-0}"

  cat >"$repo_root/bin/okf" <<EOF
#!/usr/bin/env bash
set -euo pipefail
printf '%s\n' "\$*" >>"$repo_root/okf.log"
exit $exit_code
EOF
  chmod +x "$repo_root/bin/okf"
}

run_hook() {
  local hook_path="$1"
  local cwd="$2"
  local stdout_file="$3"
  local stderr_file="$4"
  local payload="${5:-}"

  if [[ -n "$payload" ]]; then
    printf '%s' "$payload" | (
      cd "$cwd"
      bash "$hook_path"
    ) >"$stdout_file" 2>"$stderr_file"
    return
  fi

  (
    cd "$cwd"
    bash "$hook_path"
  ) >"$stdout_file" 2>"$stderr_file"
}

test_session_start_routes_to_project() {
  local tmpdir stdout stderr rc payload log
  tmpdir="$(make_fixture)"
  stdout="$tmpdir/stdout"
  stderr="$tmpdir/stderr"
  write_fake_okf "$tmpdir/repo"
  payload='{"cwd":"'"$tmpdir/repo"'","session_id":"sess-1"}'

  rc=0
  run_hook "$SESSION_START_HOOK" "$tmpdir/repo" "$stdout" "$stderr" "$payload" || rc=$?
  assert_eq "$rc" "0" "session-start exits 0"
  log="$(cat "$tmpdir/repo/okf.log")"
  assert_eq "$log" "project --repo $tmpdir/repo --project-name repo" "session-start routes to okf project"
  assert_eq "$(cat "$stdout")" "" "session-start stays quiet on stdout"
  assert_eq "$(cat "$stderr")" "" "session-start stays quiet on stderr when okf succeeds"

  rm -rf "$tmpdir"
}

test_sync_routes_to_sync_for_wave_and_session_events() {
  local tmpdir stdout stderr rc payload log
  tmpdir="$(make_fixture)"
  stdout="$tmpdir/stdout"
  stderr="$tmpdir/stderr"
  write_fake_okf "$tmpdir/repo"
  payload='{"cwd":"'"$tmpdir/repo"'","hook_event_name":"WaveBoundary"}'

  rc=0
  run_hook "$SYNC_HOOK" "$tmpdir/repo" "$stdout" "$stderr" "$payload" || rc=$?
  assert_eq "$rc" "0" "sync hook exits 0 for wave-boundary"
  log="$(cat "$tmpdir/repo/okf.log")"
  assert_eq "$log" "sync --repo $tmpdir/repo --project-name repo" "sync hook routes to okf sync"

  : >"$tmpdir/repo/okf.log"
  payload='{"cwd":"'"$tmpdir/repo"'","hook_event_name":"SessionEnd"}'
  rc=0
  run_hook "$SYNC_HOOK" "$tmpdir/repo" "$stdout" "$stderr" "$payload" || rc=$?
  assert_eq "$rc" "0" "sync hook exits 0 for session-end"
  log="$(cat "$tmpdir/repo/okf.log")"
  assert_eq "$log" "sync --repo $tmpdir/repo --project-name repo" "sync hook reuses same okf sync command"

  rm -rf "$tmpdir"
}

test_hook_failures_are_logged_and_non_fatal() {
  local tmpdir stdout stderr rc payload error_output
  tmpdir="$(make_fixture)"
  stdout="$tmpdir/stdout"
  stderr="$tmpdir/stderr"
  write_fake_okf "$tmpdir/repo" 23
  payload='{"cwd":"'"$tmpdir/repo"'"}'

  rc=0
  run_hook "$SESSION_START_HOOK" "$tmpdir/repo" "$stdout" "$stderr" "$payload" || rc=$?
  assert_eq "$rc" "0" "session-start failure stays non-fatal"
  error_output="$(cat "$stderr")"
  assert_contains "$error_output" "okf-session-start" "session-start logs hook name"
  assert_contains "$error_output" "project" "session-start logs routed verb"
  assert_contains "$error_output" "23" "session-start logs failing exit code"

  rc=0
  run_hook "$SYNC_HOOK" "$tmpdir/repo" "$stdout" "$stderr" "$payload" || rc=$?
  assert_eq "$rc" "0" "sync failure stays non-fatal"
  error_output="$(cat "$stderr")"
  assert_contains "$error_output" "okf-sync" "sync logs hook name"
  assert_contains "$error_output" "sync" "sync logs routed verb"
  assert_contains "$error_output" "23" "sync logs failing exit code"

  rm -rf "$tmpdir"
}

main() {
  [[ -f "$SESSION_START_HOOK" ]] || fail "missing hook $SESSION_START_HOOK"
  [[ -f "$SYNC_HOOK" ]] || fail "missing hook $SYNC_HOOK"
  test_session_start_routes_to_project
  test_sync_routes_to_sync_for_wave_and_session_events
  test_hook_failures_are_logged_and_non_fatal
  printf 'PASS okf hooks\n'
}

main "$@"
