#!/usr/bin/env bash

OMERON_HAS_GUM=0
OMERON_HAS_WHIPTAIL=0
OMERON_TUI_MODE="basic"

tui_detect() {
  OMERON_HAS_GUM=0
  OMERON_HAS_WHIPTAIL=0

  command -v gum >/dev/null 2>&1 && OMERON_HAS_GUM=1
  command -v whiptail >/dev/null 2>&1 && OMERON_HAS_WHIPTAIL=1

  if ((OMERON_HAS_GUM)); then
    OMERON_TUI_MODE="gum"
  elif ((OMERON_HAS_WHIPTAIL)); then
    OMERON_TUI_MODE="whiptail"
  else
    OMERON_TUI_MODE="basic"
  fi
}

tui_install_gum() {
  if ((OMERON_HAS_GUM)); then
    return 0
  fi

  if ! have pacman; then
    return 1
  fi

  printf '\033[1;36mInstalling gum for a better TUI experience...\033[0m\n'
  if sudo_run pacman -S --needed --noconfirm gum >/dev/null 2>&1; then
    command -v gum >/dev/null 2>&1 && OMERON_HAS_GUM=1
    if ((OMERON_HAS_GUM)); then
      OMERON_TUI_MODE="gum"
      return 0
    fi
  fi
  return 1
}

_strip_format() {
  local text="$1"
  text="${text//#\{bold\}/}"
  text="${text//#\{normal\}/}"
  text="${text//#\{italic\}/}"
  text="${text//#\{green\}/}"
  text="${text//#\{yellow\}/}"
  text="${text//#\{red\}/}"
  text="${text//#\{blue\}/}"
  text="${text//#\{cyan\}/}"
  text="${text//#\{magenta\}/}"
  text="${text//#\{white\}/}"
  text="${text//#\{underline\}/}"
  printf '%s\n' "$text"
}

tui_choose() {
  local prompt="$1"
  shift

  if [[ "$OMERON_TUI_MODE" == "gum" ]]; then
    gum choose "$@"
  elif [[ "$OMERON_TUI_MODE" == "whiptail" ]]; then
    local i=0
    local items=()
    for item in "$@"; do
      items+=("$i" "$item")
      ((i++))
    done
    whiptail --menu "$prompt" 20 60 10 "${items[@]}" 3>&1 1>&2 2>&3
  else
    local labels=("$@")
    printf '\n==============================\n'
    printf '  %s\n' "$(_strip_format "$prompt")"
    printf '==============================\n'
    local i
    for i in "${!labels[@]}"; do
      printf '  [%d] %s\n' "$i" "${labels[$i]}"
    done
    printf '  [x] Cancel\n'
    printf '==============================\n'
    printf '  Choice: '
    read -r choice
    if [[ "$choice" == "x" ]]; then
      return 1
    fi
    if [[ "$choice" =~ ^[0-9]+$ ]] && ((choice < ${#labels[@]})); then
      printf '%s\n' "${labels[$choice]}"
    fi
  fi
}

tui_confirm() {
  local prompt="$1"
  prompt="$(_strip_format "$prompt")"

  if [[ "$OMERON_TUI_MODE" == "gum" ]]; then
    gum confirm "$prompt"
  elif [[ "$OMERON_TUI_MODE" == "whiptail" ]]; then
    whiptail --yesno "$prompt" 10 60
  else
    printf '\n>>> %s [Y/n]: ' "$prompt"
    read -r response
    response="${response:-Y}"
    [[ "$response" =~ ^[yY](es)?$ ]]
  fi
}

tui_input() {
  local prompt="$1"
  prompt="$(_strip_format "$prompt")"

  if [[ "$OMERON_TUI_MODE" == "gum" ]]; then
    gum input --prompt "$prompt "
  elif [[ "$OMERON_TUI_MODE" == "whiptail" ]]; then
    whiptail --inputbox "$prompt" 10 60 3>&1 1>&2 2>&3
  else
    printf '%s: ' "$prompt"
    read -r response
    printf '%s\n' "$response"
  fi
}

tui_password() {
  local prompt="$1"
  prompt="$(_strip_format "$prompt")"

  if [[ "$OMERON_TUI_MODE" == "gum" ]]; then
    gum input --password --prompt "$prompt "
  elif [[ "$OMERON_TUI_MODE" == "whiptail" ]]; then
    whiptail --passwordbox "$prompt" 10 60 3>&1 1>&2 2>&3
  else
    printf '%s: ' "$prompt"
    read -rs response
    printf '\n'
    printf '%s\n' "$response"
  fi
}

tui_multiselect() {
  local prompt="$1"
  shift
  prompt="$(_strip_format "$prompt")"

  if [[ "$OMERON_TUI_MODE" == "gum" ]]; then
    gum choose --no-limit "$@"
  else
    printf '\n==============================\n'
    printf '  %s (space-separated indices)\n' "$prompt"
    printf '==============================\n'
    local i=0
    local items=("$@")
    for item in "${items[@]}"; do
      printf '  [%d] %s\n' "$i" "$item"
      ((i++))
    done
    printf '  [x] Done\n'
    printf '==============================\n'
    printf '  Select: '
    read -ra selections
    local selection
    for selection in "${selections[@]}"; do
      if [[ "$selection" =~ ^[0-9]+$ ]] && ((selection < ${#items[@]})); then
        printf '%s\n' "${items[$selection]}"
      fi
    done
  fi
}

tui_spin() {
  local title="$1"
  shift
  title="$(_strip_format "$title")"

  printf '  ▶ %s ... ' "$title"
  "$@"
  local rc=$?
  if ((rc == 0)); then
    printf '\033[1;32mOK\033[0m\n'
  else
    printf '\033[1;31mFAILED\033[0m\n'
  fi
  return $rc
}

tui_header() {
  local title="$(_strip_format "$1")"

  if [[ "$OMERON_TUI_MODE" == "gum" ]]; then
    gum style --foreground 212 --border-foreground 212 --border double --align center --width 60 --margin "1 2" --padding "1 2" "$title"
  else
    local width=50
    local line
    printf -v line '%*s' "$width" '' && line="${line// /#}"
    line="${line//#/=}"
    printf '\n'
    printf '\033[1;36m%s\033[0m\n' "$line"
    printf '\033[1;36m    %s\033[0m\n' "$title"
    printf '\033[1;36m%s\033[0m\n' "$line"
    printf '\n'
  fi
}

tui_status() {
  local ok="$1"
  local message="$2"
  message="$(_strip_format "$message")"

  if [[ "$OMERON_TUI_MODE" == "gum" ]]; then
    if ((ok == 0)); then
      gum style --foreground 10 "  ✓ $message"
    else
      gum style --foreground 9 "  ✗ $message"
    fi
  else
    if ((ok == 0)); then
      printf '  \033[1;32m✓\033[0m %s\n' "$message"
    else
      printf '  \033[1;31m✗\033[0m %s\n' "$message"
    fi
  fi
}

tui_format() {
  if [[ "$OMERON_TUI_MODE" == "gum" ]]; then
    gum format "$@"
  else
    local line
    for line in "$@"; do
      _strip_format "$line"
    done
  fi
}

tui_info() {
  local message="$(_strip_format "$1")"
  printf '  \033[1;34m▶\033[0m %s\n' "$message"
}

tui_success() {
  local message="$(_strip_format "$1")"
  printf '  \033[1;32m✓\033[0m %s\n' "$message"
}

tui_warn() {
  local message="$(_strip_format "$1")"
  printf '  \033[1;33m⚠\033[0m %s\n' "$message" >&2
}

tui_error() {
  local message="$(_strip_format "$1")"
  printf '  \033[1;31m✗\033[0m %s\n' "$message" >&2
}

tui_bold() {
  if [[ "$OMERON_TUI_MODE" == "gum" ]]; then
    gum style --bold "$1"
  else
    printf '\033[1m%s\033[0m' "$1"
  fi
}

tui_separator() {
  if [[ "$OMERON_TUI_MODE" == "gum" ]]; then
    gum style --foreground 240 "────────────────────────────────────────"
  else
    printf '  \033[2m────────────────────────────────────────\033[0m\n'
  fi
}

tui_list() {
  local items=("$@")
  local item
  for item in "${items[@]}"; do
    printf '  \033[1;36m•\033[0m %s\n' "$(_strip_format "$item")"
  done
}
