#!/usr/bin/env bash

if [ -n "${HALLUCINATE_NONINTERACTIVE_HOOK_LOADED:-}" ]; then
  return 0 2>/dev/null || exit 0
fi
HALLUCINATE_NONINTERACTIVE_HOOK_LOADED=1

: "${HALLUCINATE_STREAM_FILE:=/tmp/hallucinate_stream.json}"
: "${HALLUCINATE_ACTOR:=agent}"
HALLUCINATE_SESSION_ID="${HALLUCINATE_SESSION_ID:-$$}"
HALLUCINATE_STATE_FILE="/tmp/hallucinate_state_${HALLUCINATE_SESSION_ID}.target"
: > "$HALLUCINATE_STATE_FILE"

exec {HALLUCINATE_ORIG_STDERR_FD}>&2

_hallucinate_json_escape() {
  local s="$1"
  s=${s//\\/\\\\}
  s=${s//\"/\\\"}
  s=${s//$'\n'/\\n}
  s=${s//$'\r'/\\r}
  s=${s//$'\t'/\\t}
  printf '%s' "$s"
}

_hallucinate_path_within_workspace() {
  if [ -z "${HALLUCINATE_WORKSPACE_ROOT:-}" ]; then
    return 0
  fi
  case "$PWD/" in
    "$HALLUCINATE_WORKSPACE_ROOT"/|"$HALLUCINATE_WORKSPACE_ROOT"/*)
      return 0
      ;;
    *)
      return 1
      ;;
  esac
}

_hallucinate_log_event() {
  local exit_code="$1"
  local cmd="$2"
  local stderr_text="$3"
  local ts
  ts="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"

  _hallucinate_path_within_workspace || return 0

  mkdir -p "$(dirname "$HALLUCINATE_STREAM_FILE")"

  local cmd_esc stderr_esc cwd_esc workspace_esc
  cmd_esc="$(_hallucinate_json_escape "$cmd")"
  stderr_esc="$(_hallucinate_json_escape "$stderr_text")"
  cwd_esc="$(_hallucinate_json_escape "$PWD")"
  workspace_esc="$(_hallucinate_json_escape "${HALLUCINATE_WORKSPACE_ROOT:-}")"

  printf '{"ts":"%s","shell":"bash","actor":"%s","session":%s,"pid":%s,"cwd":"%s","workspace_root":"%s","exit_code":%s,"command":"%s","stderr":"%s"}\n' \
    "$ts" "$HALLUCINATE_ACTOR" "$HALLUCINATE_SESSION_ID" "$$" "$cwd_esc" "$workspace_esc" "$exit_code" "$cmd_esc" "$stderr_esc" \
    >> "$HALLUCINATE_STREAM_FILE"
}

_hallucinate_print_feedback() {
  local exit_code="$1"
  local cmd="$2"
  local stderr_file="$3"

  [ "$exit_code" -eq 0 ] && return 0
  command -v dont-hallucinate >/dev/null 2>&1 || return 0

  dont-hallucinate explain \
    --actor "$HALLUCINATE_ACTOR" \
    --command "$cmd" \
    --exit-code "$exit_code" \
    --stderr-file "$stderr_file" \
    >&"$HALLUCINATE_ORIG_STDERR_FD"
}

_hallucinate_stderr_router() {
  local line target
  while IFS= read -r line || [ -n "$line" ]; do
    printf '%s\n' "$line" >&"$HALLUCINATE_ORIG_STDERR_FD"
    target="$(cat "$HALLUCINATE_STATE_FILE" 2>/dev/null)"
    if [ -n "$target" ]; then
      printf '%s\n' "$line" >> "$target"
    fi
  done
}

_hallucinate_should_ignore_command() {
  case "$1" in
    _hallucinate_*|trap*|history*|local\ *|printf\ *|cat\ *|rm\ * )
      return 0
      ;;
    * )
      return 1
      ;;
  esac
}

_hallucinate_begin_capture() {
  HALLUCINATE_ERR_FILE="/tmp/hallucinate_stderr_${HALLUCINATE_SESSION_ID}.log"
  : > "$HALLUCINATE_ERR_FILE"
  printf '%s' "$HALLUCINATE_ERR_FILE" > "$HALLUCINATE_STATE_FILE"
}

_hallucinate_finish_capture() {
  local stderr_text=""
  printf '' > "$HALLUCINATE_STATE_FILE"
  if [ -n "${HALLUCINATE_ERR_FILE:-}" ] && [ -f "$HALLUCINATE_ERR_FILE" ]; then
    stderr_text="$(cat "$HALLUCINATE_ERR_FILE")"
  fi
  printf '%s' "$stderr_text"
}

exec 2> >(_hallucinate_stderr_router)

HALLUCINATE_PREV_CMD=""

_hallucinate_debug_trap() {
  local last_status=$?

  if [ -n "${HALLUCINATE_PREV_CMD:-}" ]; then
    local stderr_text
    stderr_text="$(_hallucinate_finish_capture)"
    _hallucinate_log_event "$last_status" "$HALLUCINATE_PREV_CMD" "$stderr_text"
    _hallucinate_print_feedback "$last_status" "$HALLUCINATE_PREV_CMD" "$HALLUCINATE_ERR_FILE"
    rm -f "$HALLUCINATE_ERR_FILE"
  fi

  if _hallucinate_should_ignore_command "$BASH_COMMAND"; then
    HALLUCINATE_PREV_CMD=""
    return 0
  fi

  HALLUCINATE_PREV_CMD="$BASH_COMMAND"
  _hallucinate_begin_capture
}

_hallucinate_exit_trap() {
  local last_status=$?
  if [ -n "${HALLUCINATE_PREV_CMD:-}" ]; then
    local stderr_text
    stderr_text="$(_hallucinate_finish_capture)"
    _hallucinate_log_event "$last_status" "$HALLUCINATE_PREV_CMD" "$stderr_text"
    _hallucinate_print_feedback "$last_status" "$HALLUCINATE_PREV_CMD" "$HALLUCINATE_ERR_FILE"
    rm -f "$HALLUCINATE_ERR_FILE"
  fi
}

trap '_hallucinate_debug_trap' DEBUG
trap '_hallucinate_exit_trap' EXIT
