#!/usr/bin/env bash
# osh: interactive chat interface for ollie AI agents.
set -o history

MOUNT=${OLLIE:-$HOME/mnt/ollie}
LAST=$HOME/.config/ollie/last-session

# load_session <dir>  → prints session ID for that dir, or nothing
load_session() {
    awk -F'\t' -v d="$1" 'NF==2 && $1==d {print $2; exit}' "$LAST" 2>/dev/null
}

# save_session <dir> <id>  → upserts {dir}\t{id} in $LAST
save_session() {
    local dir="$1" id="$2" tmp
    mkdir -p "$(dirname "$LAST")"
    tmp=$(mktemp)
    awk -F'\t' -v d="$dir" 'NF==2 && $1!=d' "$LAST" 2>/dev/null > "$tmp" || true
    printf '%s\t%s\n' "$dir" "$id" >> "$tmp"
    mv "$tmp" "$LAST"
}

cmd=${0##*/}
die()     { printf 'error: %s\n' "$*" >&2; exit 1; }
is_idle() { [ "$(tr -d '[:space:]' < "$S/state" 2>/dev/null)" = "idle" ]; }
drain() {
    local n
    n=$(wc -c < "$S/chat" 2>/dev/null || echo 0)
    [ "$n" -gt "$chat_off" ] && tail -c "+$((chat_off+1))" "$S/chat" | head -c "$((n-chat_off))"
    chat_off=$n
}

usage() {
    cat <<EOF
usage: $cmd [flags]

Flags:
  -new              always create a new session
  -resume           resume last session for cwd; error if none
  -session ID       attach to a specific session by ID
  -name NAME        name for new session
  -cwd DIR          working directory (default: pwd)
  -backend BACKEND  backend override (e.g. ollama, anthropic)
  -model MODEL      model override
  -agent AGENT      agent config name
  -help             show this help

Input at the prompt:
  <text>            submit prompt, stream response
  /stop             interrupt the current agent turn
  /kill             kill the session and exit
  /compact          compact conversation history
  /clear            clear conversation history
  /rn <name>        rename the session
  /cwd [path]       get or set working directory
  /agent [name]     get or set agent
  /model [name]     get or set model
  /backend [name]   get or set backend
  /models           list available models
  /backends         list available backends
  /mcp              list MCP servers
  /usage            show token usage
  /ctxsz            show context size
  /q <text>         enqueue prompt for later
  Ctrl-C            interrupt running turn (or exit if idle)
EOF
    exit 0
}

# Parse flags
new=0; resume=0; id_flag=; name=
backend=; model=; agent=; cwd=
while [ $# -gt 0 ]; do
    case $1 in
        -new)      new=1 ;;
        -resume)   resume=1 ;;
        -session)  id_flag=$2; shift ;;
        -name)     name=$2;    shift ;;
        -backend)  backend=$2; shift ;;
        -model)    model=$2;   shift ;;
        -agent)    agent=$2;   shift ;;
        -cwd)      cwd=$2;     shift ;;
        -help)     usage ;;
        *) die "unknown flag: $1" ;;
    esac
    shift
done

# Write spec to s/new
write_new() {
    {
        [ -n "$name"    ] && printf 'name=%s\n'    "$name"
        printf 'cwd=%s\n' "${cwd:-$(pwd)}"
        [ -n "$backend" ] && printf 'backend=%s\n' "$backend"
        [ -n "$model"   ] && printf 'model=%s\n'   "$model"
        [ -n "$agent"   ] && printf 'agent=%s\n'   "$agent"
        true
    } > "$MOUNT/s/new" || die "write s/new"
}

# Create a fresh session, sets $id
create_session() {
    local before d deadline
    if [ -n "$name" ]; then
        write_new
        id=$name
    else
        before=$(ls "$MOUNT/s" 2>/dev/null)
        write_new
        deadline=$(($(date +%s) + 5))
        while [ "$(date +%s)" -lt "$deadline" ]; do
            for d in $(ls "$MOUNT/s" 2>/dev/null); do
                printf '%s\n' "$before" | grep -qxF "$d" || { id=$d; return; }
            done
            sleep 0.05
        done
        die "timeout waiting for new session"
    fi
}

# Resolve session
_dir=${cwd:-$(pwd)}
if   [ -n "$id_flag" ]; then
    [ -d "$MOUNT/s/$id_flag" ] || die "session not found: $id_flag"
    id=$id_flag; printf 'session: %s (resumed)\n' "$id" >&2
elif [ "$resume" = 1 ]; then
    id=$(load_session "$_dir")
    [ -n "$id" ] && [ -d "$MOUNT/s/$id" ] || die "no resumable session for $_dir"
    printf 'session: %s (resumed)\n' "$id" >&2
elif [ "$new" = 1 ]; then
    create_session
    save_session "$_dir" "$id"
    printf 'session: %s\n' "$id" >&2
else
    id=$(load_session "$_dir")
    if [ -n "$id" ] && [ -d "$MOUNT/s/$id" ]; then
        printf 'session: %s (resumed)\n' "$id" >&2
    else
        create_session
        save_session "$_dir" "$id"
        printf 'session: %s\n' "$id" >&2
    fi
fi

S=$MOUNT/s/$id
chat_off=$(wc -c < "$S/chat" 2>/dev/null || echo 0)

trap '
    [ "$(tr -d "[:space:]" < "$S/state" 2>/dev/null)" = "idle" ] && exit
    printf "\n" >&2; printf "stop\n" > "$S/ctl"
' INT

while true; do
    printf '> '
    IFS= read -re input || break
    [ -z "$input" ] && continue
    history -s "$input"
    case "$input" in
        /stop)    printf 'stop\n'               > "$S/ctl"; continue ;;
        /kill)    printf 'kill\n'               > "$S/ctl"; break ;;
        /compact) printf 'compact\n'            > "$S/ctl"; continue ;;
        /clear)   printf 'clear\n'             > "$S/ctl"; continue ;;
        "/rn "*)  newid=${input#/rn }
                  printf 'rn %s\n' "$newid"    > "$S/ctl"
                  id=$newid; S=$MOUNT/s/$id
                  save_session "$_dir" "$id"; continue ;;
        /cwd)     cat "$S/cwd" 2>/dev/null; printf '\n'; continue ;;
        "/cwd "*) newcwd=${input#/cwd }
                  printf 'cwd %s\n' "$newcwd"  > "$S/ctl"; continue ;;
        /agent)   cat "$S/agent"   2>/dev/null; printf '\n'; continue ;;
        "/agent "*) printf '%s\n' "${input#/agent }" > "$S/agent"; continue ;;
        /model)   cat "$S/model"   2>/dev/null; printf '\n'; continue ;;
        "/model "*) printf '%s\n' "${input#/model }" > "$S/model"; continue ;;
        /backend)  cat "$S/backend" 2>/dev/null; printf '\n'; continue ;;
        "/backend "*) printf '%s\n' "${input#/backend }" > "$S/backend"; continue ;;
        /models)  cat "$S/models"  2>/dev/null; continue ;;
        /backends) cat "$MOUNT/backends" 2>/dev/null; continue ;;
        /usage)   cat "$S/usage"   2>/dev/null; continue ;;
        /ctxsz)   cat "$S/ctxsz"  2>/dev/null; continue ;;
        /mcp)     cat "$S/mcp"    2>/dev/null; continue ;;
        "/q "*)   printf '%s\n' "${input#/q }" > "$S/enqueue"
                  printf 'queued\n' >&2; continue ;;
        /*)       printf 'unknown command: %s\n' "${input%% *}" >&2; continue ;;
        *)        printf '%s' "$input" > "$S/prompt" || { printf 'submit failed\n' >&2; continue; } ;;
    esac
    sleep 0.15
    while true; do
        drain
        is_idle && { drain; printf '\n'; break; }
        sleep 0.05
    done
done
