#!/usr/bin/env bash
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
TMP_DIR=$(mktemp -d)

EDGE_PID=""
NODE_PID=""
OLLAMA_PID=""
EDGE_FD_OPEN=0

cleanup() {
    if [ "$EDGE_FD_OPEN" -eq 1 ]; then
        { echo "/exit" >&3; } 2>/dev/null || true
        exec 3>&- 2>/dev/null || true
    fi
    if [ -n "$EDGE_PID" ]; then wait "$EDGE_PID" 2>/dev/null || true; fi
    if [ -n "$NODE_PID" ]; then kill "$NODE_PID" 2>/dev/null || true; fi
    if [ -n "$OLLAMA_PID" ]; then kill "$OLLAMA_PID" 2>/dev/null || true; fi
    rm -rf "$TMP_DIR" 2>/dev/null || true
}
trap cleanup EXIT

PORT=$((31000 + RANDOM % 5000))
BOOTSTRAP_PORT=$((21000 + RANDOM % 5000))
OPENAI_PORT=$((36000 + RANDOM % 5000))
OLLAMA_PORT=$((41000 + RANDOM % 5000))
EDGE_METRICS_PORT=$((46000 + RANDOM % 5000))
NODE_METRICS_PORT=$((51000 + RANDOM % 5000))
MODEL="fake-ollama-model"

FAKE_OLLAMA="$TMP_DIR/fake_ollama.go"
cat > "$FAKE_OLLAMA" <<'EOF'
package main

import (
"encoding/json"
"log"
"net/http"
"os"
)

type chatRequest struct {
Model    string `json:"model"`
Messages []struct {
Role    string `json:"role"`
Content string `json:"content"`
} `json:"messages"`
Options struct {
NumCtx int `json:"num_ctx"`
} `json:"options"`
}

func main() {
if len(os.Args) < 2 {
log.Fatal("missing listen addr")
}
mux := http.NewServeMux()
mux.HandleFunc("/api/tags", func(w http.ResponseWriter, _ *http.Request) {
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(`{"models":[{"name":"fake-ollama-model"}]}`))
})
mux.HandleFunc("/api/chat", func(w http.ResponseWriter, r *http.Request) {
var req chatRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
if req.Model != "fake-ollama-model" {
http.Error(w, "unexpected model: "+req.Model, http.StatusBadRequest)
return
}
if req.Options.NumCtx != 262144 {
http.Error(w, "unexpected num_ctx", http.StatusBadRequest)
return
}
w.Header().Set("Content-Type", "application/x-ndjson")
_, _ = w.Write([]byte(`{"message":{"role":"assistant","thinking":"thinking..."},"done":false}` + "\n"))
if f, ok := w.(http.Flusher); ok {
f.Flush()
}
_, _ = w.Write([]byte(`{"message":{"role":"assistant","content":"IOP_OPENAI_"},"done":false}` + "\n"))
if f, ok := w.(http.Flusher); ok {
f.Flush()
}
_, _ = w.Write([]byte(`{"message":{"role":"assistant","content":"OLLAMA_OK"},"done":false}` + "\n"))
_, _ = w.Write([]byte(`{"done":true,"prompt_eval_count":5,"eval_count":2}` + "\n"))
})
log.Fatal(http.ListenAndServe(os.Args[1], mux))
}
EOF

go run "$FAKE_OLLAMA" "127.0.0.1:$OLLAMA_PORT" > "$TMP_DIR/fake_ollama.out" 2>&1 &
OLLAMA_PID=$!

wait_port() {
    local host="$1"
    local port="$2"
    local label="$3"
    local deadline=$((SECONDS + 20))
    while ! timeout 1 bash -c 'cat < /dev/null > /dev/tcp/"$1"/"$2"' _ "$host" "$port" 2>/dev/null; do
        if (( SECONDS >= deadline )); then
            echo "[openai-ollama] $label did not open on $host:$port"
            return 1
        fi
        sleep 0.2
    done
}

wait_port 127.0.0.1 "$OLLAMA_PORT" "fake ollama"

EDGE_CONFIG="$TMP_DIR/edge.yaml"
NODE_CONFIG="$TMP_DIR/node.yaml"
cat > "$EDGE_CONFIG" <<EOF
server:
  listen: "127.0.0.1:$PORT"
metrics:
  port: $EDGE_METRICS_PORT
bootstrap:
  listen: "127.0.0.1:$BOOTSTRAP_PORT"
  artifact_dir: "$TMP_DIR/artifacts"
openai:
  enabled: true
  listen: "127.0.0.1:$OPENAI_PORT"
  provider_id: "ollama-smoke-provider"
  adapter: "ollama"
  session_id: "cline"
  timeout_sec: 30
  strict_output: false
  model_routes:
    - model: "client-request-model"
      adapter: "ollama"
      target: "$MODEL"
    - model: "$MODEL"
      adapter: "ollama"
      target: "$MODEL"
console:
  adapter: ollama
  target: "$MODEL"
  session_id: default
nodes:
  - id: test-node
    alias: test-node
    token: test-token
    adapters:
      ollama:
        enabled: true
        base_url: "http://127.0.0.1:$OLLAMA_PORT"
        context_size: 262144
EOF

cat > "$NODE_CONFIG" <<EOF
transport:
  edge_addr: "127.0.0.1:$PORT"
  token: test-token
  reconnect_interval: 1s
metrics:
  port: $NODE_METRICS_PORT
node:
  id: test-node
  alias: test-node
EOF

EDGE_OUT="$TMP_DIR/edge.out"
NODE_OUT="$TMP_DIR/node.out"
mkfifo "$TMP_DIR/edge_fifo"
IOP_EDGE_CONFIG="$EDGE_CONFIG" "$REPO_ROOT/scripts/dev/edge.sh" < "$TMP_DIR/edge_fifo" > "$EDGE_OUT" 2>&1 &
EDGE_PID=$!
exec 3> "$TMP_DIR/edge_fifo"
EDGE_FD_OPEN=1

wait_port 127.0.0.1 "$PORT" "edge node transport"
wait_port 127.0.0.1 "$OPENAI_PORT" "edge openai api"

IOP_NODE_CONFIG="$NODE_CONFIG" "$REPO_ROOT/scripts/dev/node.sh" > "$NODE_OUT" 2>&1 &
NODE_PID=$!

deadline=$((SECONDS + 30))
while ! grep -q '\[node0-evt\] connected reason="registered"' "$EDGE_OUT"; do
    if (( SECONDS >= deadline )); then
        echo "[openai-ollama] node registration timed out"
        echo "=== EDGE OUTPUT ==="; cat "$EDGE_OUT"
        echo "=== NODE OUTPUT ==="; cat "$NODE_OUT"
        exit 1
    fi
    sleep 0.2
done

MODELS_OUT="$TMP_DIR/models.json"
curl -fsS "http://127.0.0.1:$OPENAI_PORT/v1/models" > "$MODELS_OUT"
grep -q "$MODEL" "$MODELS_OUT"

CHAT_OUT="$TMP_DIR/chat.json"
curl -fsS \
    -H "Content-Type: application/json" \
    -d '{"model":"client-request-model","messages":[{"role":"user","content":"say the test token"}]}' \
    "http://127.0.0.1:$OPENAI_PORT/v1/chat/completions" > "$CHAT_OUT"
grep -q "IOP_OPENAI_OLLAMA_OK" "$CHAT_OUT"
grep -q "reasoning_content" "$CHAT_OUT"

RESPONSES_OUT="$TMP_DIR/responses.json"
curl -fsS \
    -H "Content-Type: application/json" \
    -d '{"model":"client-request-model","input":"say the responses test token","stream":false,"metadata":{"request_id":"e2e-openai-ollama","task_id":"task-smoke"}}' \
    "http://127.0.0.1:$OPENAI_PORT/v1/responses" > "$RESPONSES_OUT"
grep -q "IOP_OPENAI_OLLAMA_OK" "$RESPONSES_OUT"
grep -q '"output_text"' "$RESPONSES_OUT"

STREAM_OUT="$TMP_DIR/stream.txt"
curl -fsS -N \
    -H "Content-Type: application/json" \
    -d '{"model":"client-request-model","stream":true,"messages":[{"role":"user","content":"stream the test token"}]}' \
    "http://127.0.0.1:$OPENAI_PORT/v1/chat/completions" > "$STREAM_OUT"
grep -q '"reasoning_content":"thinking..."' "$STREAM_OUT"
grep -q '"content":"IOP_OPENAI_"' "$STREAM_OUT"
grep -q 'data: \[DONE\]' "$STREAM_OUT"

SMOKE_OUT="$TMP_DIR/iop-edge-smoke-openai.txt"
(cd "$REPO_ROOT" && go run ./apps/edge/cmd/edge smoke openai \
    --model "$MODEL" \
    --base-url "http://127.0.0.1:$OPENAI_PORT" \
    --prompt "say the command smoke token" \
    --timeout 20s) > "$SMOKE_OUT"
grep -q "Step 3: Checking /v1/responses ... \[OK\]" "$SMOKE_OUT"
grep -q "IOP Edge OpenAI Smoke Test SUCCESS!" "$SMOKE_OUT"

if grep -i -E "node reported error|error run_id=|\[[^]]+-evt\] error|panic:" "$EDGE_OUT" "$NODE_OUT" >/dev/null; then
    echo "[openai-ollama] detected failure marker"
    echo "=== EDGE OUTPUT ==="; cat "$EDGE_OUT"
    echo "=== NODE OUTPUT ==="; cat "$NODE_OUT"
    exit 1
fi

echo "[openai-ollama] OpenAI-compatible Ollama serving test PASSED."
