#!/usr/bin/env rc
# sh: interactive chat interface for ollie AI agents.

MOUNT=/home/lkn/mnt/ollie
if(! ~ $#OLLIE 0) MOUNT=$OLLIE
LAST=$home/.config/ollie/last-session

fn load_session {
	awk -F'\t' -v d=$1 'NF==2 && $1==d {print $2; exit}' $LAST >[2]/dev/null
}

fn save_session {
	dir=$1
	sessid=$2
	mkdir -p `{dirname $LAST}
	tmp=`{mktemp}
	if(test -f $LAST)
		awk -F'\t' -v d=$dir 'NF==2 && $1!=d' $LAST > $tmp
	printf '%s\t%s\n' $dir $sessid >> $tmp
	mv $tmp $LAST
}

cmd=`{basename $0}
fn die {
	echo $* >[1=2]
	exit 1
}
fn cfg_get {
	awk -F= -v k=$1 '$1==k{gsub(/^[ \t]+|[ \t]+$/,"",$2); print $2; exit}' $S/cfg >[2]/dev/null
}

fn is_idle {
	~ `{cfg_get state} idle
}

fn usage {
	cat <<'EOF'
usage: sh [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
  ! <cmd>           run shell command in session cwd
  C-j               insert newline (multi-line input)
  C-m / Enter       submit input
  Ctrl-C            interrupt running turn (or exit if idle)
EOF
	exit 0
}

new=0
resume=0

while(! ~ $#* 0) {
	switch($1) {
	case -new
		new=1
	case -resume
		resume=1
	case -session
		id_flag=$2
		shift
	case -name
		name=$2
		shift
	case -backend
		backend=$2
		shift
	case -model
		model=$2
		shift
	case -agent
		agent=$2
		shift
	case -cwd
		cwd=$2
		shift
	case -help
		usage
	case *
		die 'unknown flag: '^$1
	}
	shift
}

_dir=`{pwd}
if(! ~ $#cwd 0) _dir=$cwd

fn write_new {
	{
		if(! ~ $#name 0) printf 'name=%s\n' $name
		printf 'cwd=%s\n' $_dir
		if(! ~ $#backend 0) printf 'backend=%s\n' $backend
		if(! ~ $#model 0) printf 'model=%s\n' $model
		if(! ~ $#agent 0) printf 'agent=%s\n' $agent
	} > $MOUNT/s/new
}

fn create_session {
	if(! ~ $#name 0) {
		write_new
		id=$name
		return
	}
	before=`{ls $MOUNT/s >[2]/dev/null}
	write_new
	deadline=`{expr `{date +%s} + 5}
	while(test `{date +%s} -lt $deadline) {
		for(d in `{ls $MOUNT/s >[2]/dev/null}) {
			if(! ~ $d $before) {
				id=$d
				return
			}
		}
		sleep 0.05
	}
	die 'timeout waiting for new session'
}

_picked=0

if(! ~ $#id_flag 0) {
	if(! test -d $MOUNT/s/$id_flag) die 'session not found: '^$id_flag
	id=$id_flag
	printf 'session: %s (resumed)\n' $id >[1=2]
	_picked=1
}

if(~ $_picked 0) if(~ $resume 1) {
	id=`{load_session $_dir}
	if(~ $#id 0) die 'no resumable session for '^$_dir
	if(! test -d $MOUNT/s/$id) die 'no resumable session for '^$_dir
	printf 'session: %s (resumed)\n' $id >[1=2]
	_picked=1
}

if(~ $_picked 0) if(~ $new 1) {
	create_session
	save_session $_dir $id
	printf 'session: %s\n' $id >[1=2]
	_picked=1
}

if(~ $_picked 0) {
	id=`{load_session $_dir}
	if(! ~ $#id 0) if(test -d $MOUNT/s/$id) {
		printf 'session: %s (resumed)\n' $id >[1=2]
		_picked=1
	}
	if(~ $_picked 0) {
		create_session
		save_session $_dir $id
		printf 'session: %s\n' $id >[1=2]
	}
}

S=$MOUNT/s/$id

fn sigintr {
	printf '\n' >[1=2]
	echo stop > $S/ctl
	exit 0
}

chat_off=0
if(test -f $S/chat) chat_off=`{wc -c < $S/chat}

if(! test -t 0) {
	cat > $S/prompt || die 'submit failed'
	exit 0
}

tail -n 40 $S/chat >[2]/dev/null

while(true) {
	input=`` () {$MOUNT/x/readmulti '> ' '. '}
	if(~ $#input 0) break
	if(! ~ $#input 0) {
		switch($"input) {
		case /stop
			echo stop > $S/ctl
		case /kill
			echo kill > $S/ctl
			break
		case /compact
			echo compact > $S/ctl
		case /clear
			echo clear > $S/ctl
		case /cwd
			cfg_get cwd
			echo
		case '/cwd *'
			newcwd=`{printf '%s\n' $"input | sed 's,^/cwd ,,'}
			printf 'cwd=%s\n' $newcwd > $S/cfg
		case /agent
			cfg_get agent
			echo
		case '/agent *'
			printf 'agent=%s\n' `{printf '%s\n' $"input | sed 's,^/agent ,,'} > $S/cfg
		case /model
			cfg_get model
			echo
		case '/model *'
			printf 'model=%s\n' `{printf '%s\n' $"input | sed 's,^/model ,,'} > $S/cfg
		case /backend
			cfg_get backend
			echo
		case '/backend *'
			printf 'backend=%s\n' `{printf '%s\n' $"input | sed 's,^/backend ,,'} > $S/cfg
		case /models
			cat $S/models >[2]/dev/null
		case /backends
			cat $MOUNT/backends >[2]/dev/null
		case /usage
			cat $S/usage >[2]/dev/null
		case /ctxsz
			cat $S/ctxsz >[2]/dev/null
		case /mcp
			cat $S/mcp >[2]/dev/null
		case '/rn *'
			newid=`{printf '%s\n' $"input | sed 's,^/rn ,,'}
			printf 'rn %s\n' $newid > $S/ctl
			id=$newid
			S=$MOUNT/s/$id
			save_session $_dir $id
		case '/q *'
			printf '%s\n' `{printf '%s\n' $"input | sed 's,^/q ,,'} > $S/fifo.in
			printf 'queued\n' >[1=2]
		case /*
			printf 'unknown command: %s\n' `{printf '%s\n' $"input | awk '{print $1}'} >[1=2]
		case *
			printf '%s\n' $"input > $S/prompt || { printf 'submit failed\n' >[1=2] }

			cat $S/statewait >/dev/null >[2]/dev/null

			while(! is_idle) {
				n=`{wc -c < $S/chat >[2]/dev/null}
				if(~ $#n 0) n=0
				if(test $n -gt $chat_off) {
					tail -c +`{expr $chat_off + 1} $S/chat
					chat_off=$n
				}
				sleep 0.05
			}

			n=`{wc -c < $S/chat >[2]/dev/null}
			if(~ $#n 0) n=0
			if(test $n -gt $chat_off) {
				tail -c +`{expr $chat_off + 1} $S/chat
				chat_off=$n
			}
			printf '\n'
		}
	}
}
