#!/usr/bin/env bash
# Xuai Codex provider setup for macOS/Linux.
#
# Direct run:
#   bash <(curl -fsSL https://setup.xuai.chat/install-xuai-codex.sh)

set -u

SCRIPT_VERSION='1.0.0'
PROVIDER_ID='custom'
MODEL='gpt-6-astra'
REASONING_EFFORT='medium'
BASE_URL='https://api.xuai.chat/v1'

CODEX_HOME_DIR="${CODEX_HOME:-$HOME/.codex}"
CONFIG_PATH="$CODEX_HOME_DIR/config.toml"
BACKUP_DIR="$CODEX_HOME_DIR/backup-xuai"
BACKUP_CONFIG="$BACKUP_DIR/config.toml"
MANIFEST="$BACKUP_DIR/manifest.txt"

die() { printf '[X] %s\n' "$*" >&2; exit 1; }
ok() { printf '[OK] %s\n' "$*"; }
warn() { printf '[!]  %s\n' "$*"; }
TEMP_SOURCE=''
TEMP_OUTPUT=''
cleanup_temp() {
  [ -z "$TEMP_SOURCE" ] || rm -f "$TEMP_SOURCE"
  [ -z "$TEMP_OUTPUT" ] || rm -f "$TEMP_OUTPUT"
}
trap cleanup_temp EXIT

read_tty() {
  local __var="$1" __prompt="$2" __answer=''
  if [ ! -t 0 ]; then
    IFS= read -r __answer || __answer=''
  fi
  if [ -z "$__answer" ] && [ -r /dev/tty ]; then
    printf '%s' "$__prompt" > /dev/tty
    IFS= read -r __answer < /dev/tty || __answer=''
  fi
  printf -v "$__var" '%s' "$__answer"
}

require_codex_home() {
  [ -d "$CODEX_HOME_DIR" ] || die "Codex directory was not found: $CODEX_HOME_DIR. Run Codex once first, or set CODEX_HOME."
}

manifest_value() {
  local name="$1"
  [ -f "$MANIFEST" ] || return 0
  awk -F= -v key="$name" '$1 == key { print substr($0, length(key)+2); exit }' "$MANIFEST"
}

rewrite_config() {
  local input="$1" output="$2"
  awk '
    function emit_managed() {
      print "model_provider = \"custom\""
      print "model = \"gpt-6-astra\""
      print "model_reasoning_effort = \"medium\""
      print "disable_response_storage = true"
      print "model_context_window = 1000000"
      print "model_auto_compact_token_limit = 900000"
      print ""
    }
    function is_header(line) { return line ~ /^[[:space:]]*\[[^]]+\][[:space:]]*(#.*)?$/ }
    function section_name(line, value) {
      value=line
      sub(/^[[:space:]]*\[/, "", value)
      sub(/\][[:space:]]*(#.*)?$/, "", value)
      return value
    }
    function top_key(line, value, n) {
      if (line !~ /^[[:space:]]*[A-Za-z0-9_-]+[[:space:]]*=/) return ""
      value=line
      sub(/^[[:space:]]*/, "", value)
      n=index(value, "=")
      value=substr(value, 1, n-1)
      sub(/[[:space:]]+$/, "", value)
      return value
    }
    BEGIN { inserted=0; section="" }
    {
      if (is_header($0)) {
        if (!inserted) { emit_managed(); inserted=1 }
        section=section_name($0)
        if (section == "model_providers.custom" || section ~ /^model_providers\.custom\./) next
        print
        next
      }
      if (section == "") {
        key=top_key($0)
        if (key == "model_provider" || key == "model" || key == "model_reasoning_effort" || key == "disable_response_storage" || key == "model_context_window" || key == "model_auto_compact_token_limit") next
      }
      if (section == "model_providers.custom" || section ~ /^model_providers\.custom\./) next
      print
    }
    END {
      if (!inserted) emit_managed()
      print ""
      print "[model_providers.custom]"
      print "name = \"custom\""
      print "wire_api = \"responses\""
      print "requires_openai_auth = true"
      print "base_url = \"https://api.xuai.chat/v1\""
    }
  ' "$input" > "$output"
}

validate_config() {
  local path="$1"
  [ "$(grep -Ec '^model_provider = "custom"$' "$path")" -eq 1 ] || die 'validation failed for model_provider'
  [ "$(grep -Ec '^model = "gpt-6-astra"$' "$path")" -eq 1 ] || die 'validation failed for model'
  [ "$(grep -Ec '^model_reasoning_effort = "medium"$' "$path")" -eq 1 ] || die 'validation failed for model_reasoning_effort'
  [ "$(grep -Ec '^disable_response_storage = true$' "$path")" -eq 1 ] || die 'validation failed for disable_response_storage'
  [ "$(grep -Ec '^model_context_window = 1000000$' "$path")" -eq 1 ] || die 'validation failed for model_context_window'
  [ "$(grep -Ec '^model_auto_compact_token_limit = 900000$' "$path")" -eq 1 ] || die 'validation failed for model_auto_compact_token_limit'
  grep -q '^\[model_providers\.custom\]$' "$path" || die 'validation failed: custom provider table is missing'
  grep -q '^base_url = "https://api\.xuai\.chat/v1"$' "$path" || die 'validation failed: base_url is missing'
  grep -q '^wire_api = "responses"$' "$path" || die 'validation failed: wire_api is missing'
}

install_config() {
  require_codex_home
  if [ -e "$BACKUP_DIR" ] && [ ! -f "$MANIFEST" ]; then
    die "backup directory exists but is not managed by this script: $BACKUP_DIR"
  fi

  local original_existed=0
  [ -f "$CONFIG_PATH" ] && original_existed=1
  if [ ! -d "$BACKUP_DIR" ]; then
    mkdir -p "$BACKUP_DIR" || die "cannot create $BACKUP_DIR"
    if [ "$original_existed" -eq 1 ]; then
      cp "$CONFIG_PATH" "$BACKUP_CONFIG" || die 'failed to back up config.toml'
      ok "backed up config.toml to $BACKUP_CONFIG"
    fi
    {
      printf 'script_version=%s\n' "$SCRIPT_VERSION"
      printf 'original_config_existed=%s\n' "$original_existed"
    } > "$MANIFEST" || die 'failed to initialize backup manifest'
  else
    [ "$(manifest_value original_config_existed)" = '1' ] && original_existed=1 || original_existed=0
    if [ "$original_existed" -eq 1 ] && [ ! -f "$BACKUP_CONFIG" ]; then
      die "managed backup is incomplete: $BACKUP_CONFIG"
    fi
    warn 'existing backup found; the original backup will be preserved'
  fi

  TEMP_SOURCE="$(mktemp "$CODEX_HOME_DIR/config.toml.xuai-source.XXXXXX")" || die 'cannot create temporary file'
  TEMP_OUTPUT="$(mktemp "$CODEX_HOME_DIR/config.toml.xuai-output.XXXXXX")" || die 'cannot create temporary file'
  if [ -f "$CONFIG_PATH" ]; then
    sed 's/\r$//' "$CONFIG_PATH" > "$TEMP_SOURCE" || die 'cannot read config.toml'
  else
    : > "$TEMP_SOURCE"
  fi
  rewrite_config "$TEMP_SOURCE" "$TEMP_OUTPUT" || die 'failed to rewrite config.toml'
  validate_config "$TEMP_OUTPUT"
  mv "$TEMP_OUTPUT" "$CONFIG_PATH" || die 'failed to install config.toml'
  rm -f "$TEMP_SOURCE"
  TEMP_SOURCE=''
  TEMP_OUTPUT=''

  {
    printf 'script_version=%s\n' "$SCRIPT_VERSION"
    printf 'installed_at=%s\n' "$(date '+%Y-%m-%d %H:%M:%S')"
    printf 'original_config_existed=%s\n' "$original_existed"
    printf 'provider=%s\n' "$PROVIDER_ID"
    printf 'model=%s\n' "$MODEL"
    printf 'base_url=%s\n' "$BASE_URL"
  } > "$MANIFEST" || die 'failed to write manifest'

  ok "updated $CONFIG_PATH"
  printf '\nManaged settings:\n'
  printf '  model_provider = "custom"\n  model = "gpt-6-astra"\n  model_reasoning_effort = "medium"\n  disable_response_storage = true\n  model_context_window = 1000000\n  model_auto_compact_token_limit = 900000\n'
  printf '  [model_providers.custom] base_url = "%s"\n\n' "$BASE_URL"
  warn 'Restart Codex completely for the configuration to take effect.'
  printf 'Run this script again and choose restore to return to the pre-install config.\n'
}

restore_config() {
  require_codex_home
  [ -d "$BACKUP_DIR" ] || die "no backup found at $BACKUP_DIR"
  local original_existed=0
  [ "$(manifest_value original_config_existed)" = '1' ] && original_existed=1
  printf 'This will restore the original config from %s.\n' "$BACKUP_DIR"
  warn 'Changes made to config.toml after installation will be replaced.'
  local answer=''
  read_tty answer 'Continue? Type y to continue: '
  case "$answer" in y|Y|yes|YES) ;; *) printf 'Cancelled; no files were changed.\n'; return ;; esac

  if [ "$original_existed" -eq 1 ]; then
    [ -f "$BACKUP_CONFIG" ] || die "backup is incomplete: $BACKUP_CONFIG"
    cp "$BACKUP_CONFIG" "$CONFIG_PATH" || die 'failed to restore config.toml'
    ok 'restored config.toml'
  elif [ -f "$CONFIG_PATH" ]; then
    rm -f "$CONFIG_PATH" || die 'failed to remove generated config.toml'
    ok 'removed config.toml (it did not exist before installation)'
  fi
  rm -rf "$BACKUP_DIR" || die 'failed to remove Xuai backup metadata'
  ok 'removed Xuai backup metadata'
  warn 'Restart Codex completely for the restoration to take effect.'
}

show_menu() {
  printf 'Xuai Codex setup v%s\nCodex directory: %s\n\n' "$SCRIPT_VERSION" "$CODEX_HOME_DIR"
  printf '  1. Install/update the Xuai custom provider\n  9. Restore the pre-install Codex config\n'
  local choice=''
  read_tty choice 'Choose 1 or 9: '
  case "$choice" in
    1) install_config ;;
    9) restore_config ;;
    *) die 'invalid choice; use 1 or 9' ;;
  esac
}

case "${1:-menu}" in
  menu) show_menu ;;
  install) install_config ;;
  restore) restore_config ;;
  *) die 'usage: install-xuai-codex.sh [install|restore]' ;;
esac
