#!/usr/bin/env bash
# prefix-match harness for logs-read.sh.
#
# introduced 8-char-prefix resolution collapses the
# writer's two-shape contract to one (`claude-agent-stream-<sessionKey>.log`).
# The prefix match still applies, now against a single basename shape.
#
# Cases:
#   1. 8-char prefix resolves a full sessionKey-named file.
#   2. Multiple matches → ambiguous-prefix, exit 1, never picks silently.
#   3. More-specific prefix disambiguates.
#   4. Zero matches → exit 1 with file-not-found trailer.
#   5. Full 36-char sessionKey still resolves (regression boundary).
#   6. Every per-session type (agent-stream, session, error, public)
#      resolves under prefix-match.
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LOGS_READ="$SCRIPT_DIR/../logs-read.sh"
if [[ ! -x "$LOGS_READ" ]]; then
  echo "FATAL: $LOGS_READ not executable" >&2
  exit 1
fi

PASS=0
FAIL=0

setup_install_tree() {
  local root="$1"
  mkdir -p "$root/platform/scripts"
  mkdir -p "$root/data/accounts/acct-test/logs"
  mkdir -p "$HOME/.$(basename "$root")/logs"
  ln -sf "$LOGS_READ" "$root/platform/scripts/logs-read.sh"
  echo "$root/platform/scripts/logs-read.sh"
}

cleanup_install_tree() {
  local root="$1"
  rm -rf "$root"
  rm -rf "$HOME/.$(basename "$root")"
}

run_case() {
  local name="$1"
  shift
  echo ""
  echo "=== CASE: $name ==="
  if "$@"; then
    PASS=$((PASS + 1))
    echo "PASS: $name"
  else
    FAIL=$((FAIL + 1))
    echo "FAIL: $name"
  fi
}

case_8char_prefix_resolves_full() {
  local root="/tmp/maxy-prefix-test-1-$$"
  local script
  script=$(setup_install_tree "$root")
  local logdir="$root/data/accounts/acct-test/logs"
  local sk="abcd1234-5678-90ab-cdef-1234567890ab"
  echo "sentinel-1" > "$logdir/claude-agent-stream-${sk}.log"

  local rc=0
  local stdout
  stdout=$("$script" "abcd1234" agent-stream 2>/dev/null) || rc=$?
  cleanup_install_tree "$root"

  [[ $rc -eq 0 ]] || { echo "  expected exit 0, got $rc"; return 1; }
  [[ "$stdout" == *"sentinel-1"* ]] || { echo "  missing sentinel"; return 1; }
  return 0
}

case_ambiguous_prefix_refuses() {
  local root="/tmp/maxy-prefix-test-2-$$"
  local script
  script=$(setup_install_tree "$root")
  local logdir="$root/data/accounts/acct-test/logs"
  echo "a" > "$logdir/claude-agent-stream-abcd1111.log"
  echo "b" > "$logdir/claude-agent-stream-abcd2222.log"

  local rc=0
  "$script" "abcd" agent-stream >/dev/null 2>/tmp/prefix-stderr-2-$$ || rc=$?
  local stderr
  stderr=$(cat /tmp/prefix-stderr-2-$$)
  rm -f /tmp/prefix-stderr-2-$$
  cleanup_install_tree "$root"

  [[ $rc -eq 1 ]] || { echo "  expected exit 1, got $rc"; return 1; }
  [[ "$stderr" == *"ambiguous-prefix"* ]] || { echo "  stderr missing ambiguous-prefix: $stderr"; return 1; }
  return 0
}

case_more_specific_prefix_resolves() {
  local root="/tmp/maxy-prefix-test-3-$$"
  local script
  script=$(setup_install_tree "$root")
  local logdir="$root/data/accounts/acct-test/logs"
  echo "a" > "$logdir/claude-agent-stream-abcd1111.log"
  echo "b" > "$logdir/claude-agent-stream-abcd2222.log"

  local rc=0
  local stdout
  stdout=$("$script" "abcd1111" agent-stream 2>/dev/null) || rc=$?
  cleanup_install_tree "$root"

  [[ $rc -eq 0 ]] || { echo "  expected exit 0, got $rc"; return 1; }
  [[ "$stdout" == *"a"* ]] || { echo "  missing sentinel"; return 1; }
  return 0
}

case_zero_match_miss() {
  local root="/tmp/maxy-prefix-test-4-$$"
  local script
  script=$(setup_install_tree "$root")

  local rc=0
  "$script" "nomatch1" agent-stream >/dev/null 2>/tmp/prefix-stderr-4-$$ || rc=$?
  local stderr
  stderr=$(cat /tmp/prefix-stderr-4-$$)
  rm -f /tmp/prefix-stderr-4-$$
  cleanup_install_tree "$root"

  [[ $rc -eq 1 ]] || { echo "  expected exit 1, got $rc"; return 1; }
  [[ "$stderr" == *"file-not-found"* ]] || { echo "  stderr missing file-not-found"; return 1; }
  return 0
}

case_full_sessionkey_resolves() {
  local root="/tmp/maxy-prefix-test-5-$$"
  local script
  script=$(setup_install_tree "$root")
  local logdir="$root/data/accounts/acct-test/logs"
  local sk="11111111-2222-3333-4444-555555555555"
  echo "sentinel-5" > "$logdir/claude-agent-stream-${sk}.log"

  local rc=0
  local stdout
  stdout=$("$script" "$sk" agent-stream 2>/dev/null) || rc=$?
  cleanup_install_tree "$root"

  [[ $rc -eq 0 ]] || { echo "  expected exit 0, got $rc"; return 1; }
  [[ "$stdout" == *"sentinel-5"* ]] || { echo "  missing sentinel"; return 1; }
  return 0
}

case_every_per_session_type() {
  local root="/tmp/maxy-prefix-test-6-$$"
  local script
  script=$(setup_install_tree "$root")
  local logdir="$root/data/accounts/acct-test/logs"
  local sk="abcdef00-0000-0000-0000-000000000000"
  echo "stream" > "$logdir/claude-agent-stream-${sk}.log"
  echo "err"    > "$logdir/claude-agent-stderr-${sk}.log"
  echo "sse"    > "$logdir/sse-events-${sk}.log"
  echo "pub"    > "$logdir/public-agent-stream-${sk}.log"

  local ok=1
  for type in agent-stream error session public; do
    local out
    out=$("$script" "abcdef00" "$type" 2>/dev/null) || ok=0
    case "$type" in
      agent-stream) [[ "$out" == *"stream"* ]] || ok=0 ;;
      error)        [[ "$out" == *"err"* ]]    || ok=0 ;;
      session)      [[ "$out" == *"sse"* ]]    || ok=0 ;;
      public)       [[ "$out" == *"pub"* ]]    || ok=0 ;;
    esac
  done
  cleanup_install_tree "$root"
  [[ $ok -eq 1 ]] || { echo "  one or more per-session types failed to resolve"; return 1; }
  return 0
}

# sk_<hex16> writer-side format must resolve via
# the underscore-bearing regex `^[a-zA-Z0-9_-]+$`. Pre-1010 the regex
# rejected `_`, leaving every post-1008 stream log unretrievable.
case_sk_underscore_prefix_resolves() {
  local root="/tmp/maxy-prefix-test-7-$$"
  local script
  script=$(setup_install_tree "$root")
  local logdir="$root/data/accounts/acct-test/logs"
  local sk="sk_16e0eeb035cf52ef"
  echo "sentinel-sk" > "$logdir/claude-agent-stream-${sk}.log"

  local rc=0
  local stdout
  stdout=$("$script" "sk_16e0e" agent-stream 2>/dev/null) || rc=$?
  cleanup_install_tree "$root"

  [[ $rc -eq 0 ]] || { echo "  expected exit 0, got $rc"; return 1; }
  [[ "$stdout" == *"sentinel-sk"* ]] || { echo "  missing sentinel"; return 1; }
  return 0
}

# shell metacharacters must still be rejected. The regex widen
# adds `_` only; `;`, `*`, `$`, `?`, `[` etc. must still hit the reject path
# and exit 2, otherwise user input would escape literal matching in the glob.
# Also asserts the `[logs-read] regex-rejected` observability line lands in
# server.log so the adherence runner can see writer/reader divergence.
case_shell_metachar_still_rejected() {
  local root="/tmp/maxy-prefix-test-8-$$"
  local script
  script=$(setup_install_tree "$root")
  local server_log="$HOME/.$(basename "$root")/logs/server.log"
  : > "$server_log"

  local rc=0
  "$script" "abc;rm" agent-stream >/dev/null 2>/tmp/prefix-stderr-8-$$ || rc=$?
  local stderr
  stderr=$(cat /tmp/prefix-stderr-8-$$)
  rm -f /tmp/prefix-stderr-8-$$
  local server_log_contents
  server_log_contents=$(cat "$server_log" 2>/dev/null || echo "")
  cleanup_install_tree "$root"

  [[ $rc -eq 2 ]] || { echo "  expected exit 2, got $rc"; return 1; }
  [[ "$stderr" == *"invalid characters"* ]] || { echo "  stderr missing 'invalid characters': $stderr"; return 1; }
  [[ "$server_log_contents" == *"[logs-read] regex-rejected"* ]] || { echo "  server.log missing regex-rejected line: $server_log_contents"; return 1; }
  [[ "$server_log_contents" == *"sample=;"* ]] || { echo "  server.log missing sample=;: $server_log_contents"; return 1; }
  return 0
}

run_case "8-char prefix resolves full sessionKey file"   case_8char_prefix_resolves_full
run_case "ambiguous prefix refuses to pick"              case_ambiguous_prefix_refuses
run_case "more-specific prefix disambiguates"            case_more_specific_prefix_resolves
run_case "zero matches → file-not-found"                 case_zero_match_miss
run_case "full 36-char sessionKey resolves"              case_full_sessionkey_resolves
run_case "every per-session type resolves"               case_every_per_session_type
run_case "sk_ underscore prefix resolves"     case_sk_underscore_prefix_resolves
run_case "shell metacharacter still rejected" case_shell_metachar_still_rejected

echo ""
echo "================================================"
echo " Passed: $PASS / Failed: $FAIL"
echo "================================================"
[[ $FAIL -eq 0 ]]
