#!/usr/bin/env bash
# 09_failure_modes.sh — GOLAKE-080..085.
# Verifies the system fails cleanly: 4xx for malformed input, 404 for
# missing resources, structured error bodies. Per the spec: "Do not
# hide failures behind retries unless documented."

set -uo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${SCRIPT_DIR}/../lib/env.sh"
source "${SCRIPT_DIR}/../lib/http.sh"
source "${SCRIPT_DIR}/../lib/assert.sh"

CASE_ID="GOLAKE-080-085"
CASE_NAME="Failure modes — 4xx not 5xx, structured errors"
CASE_TYPE="contract"
if [ "${1:-}" = "--metadata-only" ]; then return 0 2>/dev/null || exit 0; fi

# ── GOLAKE-080: malformed JSON → 4xx, never 5xx, never silent 200 ───
JUNK='not-valid-json{[]}'
ENDPOINTS=(
    "catalog_register:${PROOF_GATEWAY_URL}/v1/catalog/register"
    "ingest:${PROOF_GATEWAY_URL}/v1/ingest"
    "sql:${PROOF_GATEWAY_URL}/v1/sql"
    "embed:${PROOF_GATEWAY_URL}/v1/embed"
)
for spec in "${ENDPOINTS[@]}"; do
    IFS=':' read -r name url <<< "$spec"
    proof_post "$CASE_ID" "malformed_${name}" "$url" "application/json" "$JUNK" >/dev/null
    proof_assert_status_4xx "$CASE_ID" "${name}: malformed JSON → 4xx" "malformed_${name}"
done

# ── GOLAKE-081: missing required field → 400 ──────────────────────
proof_post "$CASE_ID" "missing_required_catalog" \
    "${PROOF_GATEWAY_URL}/v1/catalog/register" \
    "application/json" '{}' >/dev/null
proof_assert_status_4xx "$CASE_ID" "catalog/register: empty body → 4xx" "missing_required_catalog"

proof_post "$CASE_ID" "missing_required_vector_create" \
    "${PROOF_GATEWAY_URL}/v1/vectors/index" \
    "application/json" '{"name":"missing_dim_test"}' >/dev/null
proof_assert_status_4xx "$CASE_ID" "vectors/index: missing dimension → 4xx" "missing_required_vector_create"

proof_post "$CASE_ID" "missing_required_embed" \
    "${PROOF_GATEWAY_URL}/v1/embed" \
    "application/json" '{}' >/dev/null
proof_assert_status_4xx "$CASE_ID" "embed: missing texts → 4xx" "missing_required_embed"

# ── GOLAKE-082: bad SQL → 4xx, error body present ────────────────
proof_post "$CASE_ID" "bad_sql_syntax" \
    "${PROOF_GATEWAY_URL}/v1/sql" \
    "application/json" '{"sql":"NOT VALID SQL HERE"}' >/dev/null
proof_assert_status_4xx "$CASE_ID" "queryd: bad SQL → 4xx" "bad_sql_syntax"
err_body=$(proof_body_of "$CASE_ID" "bad_sql_syntax")
proof_assert_ne "$CASE_ID" "queryd: bad SQL response body non-empty" "" "$err_body"

# ── GOLAKE-083: vector dim mismatch → 4xx ────────────────────────
DIM_IDX="proof_dim_mismatch_test"
proof_delete "$CASE_ID" "dim_pre_clean" \
    "${PROOF_GATEWAY_URL}/v1/vectors/index/${DIM_IDX}" >/dev/null
proof_post "$CASE_ID" "dim_create" \
    "${PROOF_GATEWAY_URL}/v1/vectors/index" \
    "application/json" "{\"name\":\"${DIM_IDX}\",\"dimension\":3}" >/dev/null
# Wrong-shape add — vectord wants `items` not `vectors`. Use correct
# field name; the dim mismatch is the actual failure mode under test.
proof_post "$CASE_ID" "dim_mismatch_add" \
    "${PROOF_GATEWAY_URL}/v1/vectors/index/${DIM_IDX}/add" \
    "application/json" '{"items":[{"id":"x","vector":[1,2,3,4]}]}' >/dev/null
proof_assert_status_4xx "$CASE_ID" "vectord: dim mismatch on add → 4xx" "dim_mismatch_add"
proof_delete "$CASE_ID" "dim_post_clean" \
    "${PROOF_GATEWAY_URL}/v1/vectors/index/${DIM_IDX}" >/dev/null

# ── GOLAKE-084: missing storage object → 404 ──────────────────────
proof_get "$CASE_ID" "missing_object" \
    "${PROOF_GATEWAY_URL}/v1/storage/get/proof_definitely_not_a_key_xyz_$(date +%N)" >/dev/null
proof_assert_eq "$CASE_ID" "storage/get on missing key → 404" "404" \
    "$(proof_status_of "$CASE_ID" "missing_object")"

# ── GOLAKE-085: duplicate vector ID — informational ──────────────
DUP_IDX="proof_dup_test"
proof_delete "$CASE_ID" "dup_pre_clean" \
    "${PROOF_GATEWAY_URL}/v1/vectors/index/${DUP_IDX}" >/dev/null
proof_post "$CASE_ID" "dup_create" \
    "${PROOF_GATEWAY_URL}/v1/vectors/index" \
    "application/json" "{\"name\":\"${DUP_IDX}\",\"dimension\":2}" >/dev/null
proof_post "$CASE_ID" "dup_add_first" \
    "${PROOF_GATEWAY_URL}/v1/vectors/index/${DUP_IDX}/add" \
    "application/json" '{"items":[{"id":"d1","vector":[1,0]}]}' >/dev/null
proof_post "$CASE_ID" "dup_add_second" \
    "${PROOF_GATEWAY_URL}/v1/vectors/index/${DUP_IDX}/add" \
    "application/json" '{"items":[{"id":"d1","vector":[0,1]}]}' >/dev/null

dup_first=$(proof_status_of "$CASE_ID" "dup_add_first")
dup_second=$(proof_status_of "$CASE_ID" "dup_add_second")
proof_assert_eq "$CASE_ID" "dup add first → 200" "200" "$dup_first"
proof_skip "$CASE_ID" "dup-id behavior recorded (informational)" \
    "first=${dup_first} second=${dup_second} — see raw/http/${CASE_ID}/dup_add_*.json for full record"
proof_delete "$CASE_ID" "dup_post_clean" \
    "${PROOF_GATEWAY_URL}/v1/vectors/index/${DUP_IDX}" >/dev/null
