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

BASE_URL='https://contact.robinmollah.com'
TEMP_DIR=""
TRANSCRIPT_FILE=""
PROFILE_TEXT=""
SESSION_ID=""
CLIENT_TOKEN=""
CURSOR="0"
RUNNING=1
TTY_PATH="/dev/tty"
INPUT_BUFFER=""
PROMPT_TICK=0

cleanup() {
  if [ -n "$SESSION_ID" ] && [ -n "$CLIENT_TOKEN" ]; then
    curl -fsS --connect-timeout 1 --max-time 2 -X POST "$BASE_URL/api/session/$SESSION_ID/close" \
      -H "Authorization: Bearer $CLIENT_TOKEN" \
      >/dev/null 2>&1 || true
  fi

  if [ -n "$TEMP_DIR" ] && [ -d "$TEMP_DIR" ]; then
    rm -rf "$TEMP_DIR"
  fi

  printf '\n'
}

require_command() {
  if ! command -v "$1" >/dev/null 2>&1; then
    printf 'Missing required command: %s\n' "$1" >&2
    exit 1
  fi
}

require_tty() {
  if [ ! -r "$TTY_PATH" ] || [ ! -w "$TTY_PATH" ]; then
    printf '%s\n' "This script needs an interactive terminal (/dev/tty)." >&2
    exit 1
  fi
}

tty_print() {
  printf '%s' "$1" > "$TTY_PATH"
}

draw_ui() {
  tty_print $'\033[2J\033[H'
  cat <<'EOF'
========================================
  ____   ___  ____ ___ _   _
 |  _ \ / _ \| __ )_ _| \ | |
 | |_) | | | |  _ \| ||  \| |
 |  _ <| |_| | |_) | || |\  |
 |_| \_\\___/|____/___|_| \_|

  __  __  ___  _     _        _   _
 |  \/  |/ _ \| |   | |      / \ | |
 | |\/| | | | | |   | |     / _ \| |
 | |  | | |_| | |___| |___ / ___ \ |
 |_|  |_|\___/|_____|_____/_/   \_\_|
========================================
EOF
  printf '\n'
  printf '%s\n' "Direct terminal contact with Robin."
  printf '%s\n' "Use :about if you want the full profile and links."
  printf '\n'
  printf '%s\n' "----------------------------------------"
  printf '%s\n' " Conversation"
  printf '%s\n' "----------------------------------------"

  if [ -s "$TRANSCRIPT_FILE" ]; then
    cat "$TRANSCRIPT_FILE"
  else
    printf '%s\n' "No messages yet. Type something and press Enter."
  fi

  printf '\n'
  printf '%s\n' "Commands: :help  :about  :clear  :quit"
  printf '\n'
}

append_transcript() {
  printf '%s\n' "$1" >> "$TRANSCRIPT_FILE"
}

render_sending_progress() {
  local frame="$1"
  local width=18
  local filled=$(((frame % width) + 1))
  local remaining=$((width - filled))
  local bar
  local padding

  bar="$(printf '%*s' "$filled" '')"
  bar="$(printf '%s' "$bar" | tr ' ' '=')"
  padding="$(printf '%*s' "$remaining" '')"

  tty_print $'\r\033[2K'
  tty_print "Sending [$bar>$padding]"
}

clear_status_line() {
  tty_print $'\r\033[2K'
}

render_prompt() {
  tty_print $'\r\033[2K'
  tty_print "> $INPUT_BUFFER"
}

fetch_profile() {
  PROFILE_TEXT="$(curl -fsSL "$BASE_URL/api/profile?format=text")"
}

create_session() {
  local name="$1"
  local shell_vars

  shell_vars="$(curl -fsSL -X POST "$BASE_URL/api/session?format=shell" \
    -H 'Content-Type: application/json' \
    --data "$(printf '{"name":"%s"}' "$(printf '%s' "$name" | sed 's/["\\]/\\&/g')")")"

  eval "$shell_vars"
}

fetch_events() {
  local wait_flag="${1:-1}"
  local shell_vars
  shell_vars="$(curl -fsSL "$BASE_URL/api/session/$SESSION_ID/events?cursor=$CURSOR&format=shell&wait=$wait_flag" \
    -H "Authorization: Bearer $CLIENT_TOKEN")"

  eval "$shell_vars"

  local index=0
  while [ "$index" -lt "$EVENT_COUNT" ]; do
    eval "local kind=\${EVENT_${index}_KIND}"
    eval "local text=\${EVENT_${index}_TEXT}"
    eval "local ts=\${EVENT_${index}_TS}"

    case "$kind" in
      info)
        append_transcript "[$ts] info: $text"
        ;;
      visitor_message_ack)
        append_transcript "[$ts] you: $text"
        ;;
      robin_message)
        append_transcript "[$ts] robin: $text"
        ;;
      session_closed)
        append_transcript "[$ts] session: $text"
        RUNNING=0
        ;;
      *)
        append_transcript "[$ts] $kind: $text"
        ;;
    esac

    index=$((index + 1))
  done

  CURSOR="$NEXT_CURSOR"
}

post_message() {
  curl -fsSL -X POST "$BASE_URL/api/session/$SESSION_ID/message" \
    -H 'Content-Type: application/json' \
    -H "Authorization: Bearer $CLIENT_TOKEN" \
    --data "$(printf '{"text":"%s"}' "$(printf '%s' "$1" | sed 's/["\\]/\\&/g')")" \
    >/dev/null
}

send_message_with_progress() {
  local text="$1"
  local error_file="$TEMP_DIR/send-error.log"
  local frame=0
  local min_frames=3

  : > "$error_file"
  post_message "$text" 2>"$error_file" &
  local request_pid=$!

  while kill -0 "$request_pid" 2>/dev/null || [ "$frame" -lt "$min_frames" ]; do
    render_sending_progress "$frame"
    frame=$((frame + 1))
    sleep 0.08
  done

  wait "$request_pid"
  local status=$?
  clear_status_line
  rm -f "$error_file"
  return "$status"
}

print_help() {
  append_transcript "[local] Commands:"
  append_transcript "[local]   :help   Show available commands"
  append_transcript "[local]   :about  Reprint profile information"
  append_transcript "[local]   :clear  Clear the transcript"
  append_transcript "[local]   :quit   Close this session"
}

main_loop() {
  while [ "$RUNNING" -eq 1 ]; do
    if [ "$PROMPT_TICK" -eq 0 ]; then
      fetch_events 0
      draw_ui
      render_prompt
    fi

    PROMPT_TICK=$(((PROMPT_TICK + 1) % 10))

    local char=""
    if IFS= read -r -s -n 1 -t 1 char < "$TTY_PATH"; then
      case "$char" in
        "")
          local line="$INPUT_BUFFER"
          INPUT_BUFFER=""
          PROMPT_TICK=0
          tty_print $'\n'
          case "$line" in
            :help)
              print_help
              ;;
            :about)
              append_transcript "[local] Profile"
              while IFS= read -r about_line; do
                append_transcript "[local] $about_line"
              done <<EOF
$PROFILE_TEXT
EOF
              ;;
            :clear)
              : > "$TRANSCRIPT_FILE"
              ;;
            :quit)
              RUNNING=0
              append_transcript "[local] Closing session."
              draw_ui
              exit 0
              ;;
            *)
              if [ -n "$line" ]; then
                if send_message_with_progress "$line"; then
                  fetch_events
                else
                  append_transcript "[local] Failed to send message."
                fi
              fi
              ;;
          esac
          ;;
        $'\n'|$'\r')
          local line="$INPUT_BUFFER"
          INPUT_BUFFER=""
          PROMPT_TICK=0
          tty_print $'\n'
          case "$line" in
            :help)
              print_help
              ;;
            :about)
              append_transcript "[local] Profile"
              while IFS= read -r about_line; do
                append_transcript "[local] $about_line"
              done <<EOF
$PROFILE_TEXT
EOF
              ;;
            :clear)
              : > "$TRANSCRIPT_FILE"
              ;;
            :quit)
              RUNNING=0
              append_transcript "[local] Closing session."
              draw_ui
              exit 0
              ;;
            "")
              :
              ;;
            *)
              if send_message_with_progress "$line"; then
                fetch_events
              else
                append_transcript "[local] Failed to send message."
              fi
              ;;
          esac
          ;;
        $'\177'|$'\010')
          if [ -n "$INPUT_BUFFER" ]; then
            INPUT_BUFFER="${INPUT_BUFFER%?}"
            render_prompt
          fi
          ;;
        *)
          INPUT_BUFFER="$INPUT_BUFFER$char"
          render_prompt
          ;;
      esac
    elif [ "$PROMPT_TICK" -eq 0 ]; then
      render_prompt
    fi
  done
}

bootstrap() {
  require_command bash
  require_command curl
  require_command mktemp
  require_command tput
  require_tty

  TEMP_DIR="$(mktemp -d)"
  TRANSCRIPT_FILE="$TEMP_DIR/transcript.txt"
  trap cleanup EXIT INT TERM

  fetch_profile
  draw_ui

  local name=""
  while [ -z "$name" ]; do
    tty_print 'Your name: '
    IFS= read -r name < "$TTY_PATH"
    name="$(printf '%s' "$name" | sed 's/^ *//; s/ *$//')"
  done

  create_session "$name"
  fetch_events
  draw_ui
  main_loop
}

bootstrap
