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

DOCDOT_VERSION="${DOCDOT_VERSION:-latest}"
DOCDOT_INSTALL_BASE_URL="${DOCDOT_INSTALL_BASE_URL:-https://dl.docdot.ai/releases/docdot}"
DOCDOT_CONVERTER_INSTALL_BASE_URL="${DOCDOT_CONVERTER_INSTALL_BASE_URL:-https://dl.docdot.ai/releases/docdot-converter}"
DOCDOT_HOME="${DOCDOT_HOME:-$HOME/.docdot}"
DOCDOT_BIN_DIR="${DOCDOT_BIN_DIR:-$HOME/.local/bin}"
DOCDOT_UNAME_S_OVERRIDE="${DOCDOT_UNAME_S:-}"
DOCDOT_UNAME_M_OVERRIDE="${DOCDOT_UNAME_M:-}"
COLOR_RESET=""
COLOR_BOLD=""
COLOR_BLUE=""
COLOR_GREEN=""
COLOR_YELLOW=""
COLOR_RED=""

usage() {
  cat <<'EOF'
Install docdot on Unix-like systems.

Usage:
  curl -fsSL <install-url> | bash
  curl -fsSL <install-url> | bash -s -- [--skip-skills-install]

Options:
  --skip-skills-install    Do not install or replace agent PDF skills.

Environment:
  DOCDOT_VERSION          Release version tag. Defaults to latest.
  DOCDOT_INSTALL_BASE_URL Release binary root URL. Defaults to https://dl.docdot.ai/releases/docdot.
  DOCDOT_CONVERTER_INSTALL_BASE_URL
                          Converter release binary root URL. Defaults to https://dl.docdot.ai/releases/docdot-converter.
  DOCDOT_HOME             Install root. Defaults to ~/.docdot.
  DOCDOT_BIN_DIR          Binary directory. Defaults to ~/.local/bin.
  DOCDOT_UNAME_S          Override uname -s for tests.
  DOCDOT_UNAME_M          Override uname -m for tests.
EOF
}

setup_colors() {
  if [ -t 1 ] && [ -z "${NO_COLOR:-}" ] && [ "${TERM:-}" != "dumb" ]; then
    COLOR_RESET="$(printf '\033[0m')"
    COLOR_BOLD="$(printf '\033[1m')"
    COLOR_BLUE="$(printf '\033[34m')"
    COLOR_GREEN="$(printf '\033[32m')"
    COLOR_YELLOW="$(printf '\033[33m')"
    COLOR_RED="$(printf '\033[31m')"
  fi
}

log() {
  printf '%s[docdot install]%s %s\n' "$COLOR_BOLD" "$COLOR_RESET" "$*" >&2
}

step() {
  printf '%s%s[docdot install]%s %s\n' "$COLOR_BLUE" "🚀 " "$COLOR_RESET" "$*" >&2
}

success() {
  printf '%s%s[docdot install]%s %s\n' "$COLOR_GREEN" "✅ " "$COLOR_RESET" "$*" >&2
}

warn() {
  printf '%s%s[docdot install]%s %s\n' "$COLOR_YELLOW" "⚠️  " "$COLOR_RESET" "$*" >&2
}

die() {
  printf '%s%s[docdot install]%s ERROR: %s\n' "$COLOR_RED" "❌ " "$COLOR_RESET" "$*" >&2
  exit 1
}

command_exists() {
  command -v "$1" >/dev/null 2>&1
}

shell_name() {
  local shell_path="${SHELL:-}"
  printf '%s' "${shell_path##*/}"
}

uname_s() {
  if [ -n "$DOCDOT_UNAME_S_OVERRIDE" ]; then
    printf '%s' "$DOCDOT_UNAME_S_OVERRIDE"
    return 0
  fi
  uname -s
}

uname_m() {
  if [ -n "$DOCDOT_UNAME_M_OVERRIDE" ]; then
    printf '%s' "$DOCDOT_UNAME_M_OVERRIDE"
    return 0
  fi
  uname -m
}

detect_platform() {
  local os
  local arch

  case "$(uname_s)" in
    Darwin)
      os="darwin"
      ;;
    Linux)
      os="linux"
      ;;
    *)
      die "Unsupported OS/architecture: $(uname_s)/$(uname_m)"
      ;;
  esac

  case "$(uname_m)" in
    x86_64 | amd64)
      arch="amd64"
      ;;
    arm64 | aarch64)
      arch="arm64"
      ;;
    *)
      die "Unsupported OS/architecture: $(uname_s)/$(uname_m)"
      ;;
  esac

  printf '%s-%s' "$os" "$arch"
}

download_to_file() {
  local url="$1"
  local output="$2"

  if command_exists curl; then
    if [ -t 1 ]; then
      curl --progress-bar -fL "$url" -o "$output"
    else
      curl -fsSL "$url" -o "$output"
    fi
    return $?
  fi

  if command_exists wget; then
    if [ -t 1 ]; then
      wget --show-progress -O "$output" "$url"
    else
      wget -q -O "$output" "$url"
    fi
    return $?
  fi

  return 1
}

shell_rc_candidates() {
  case "$(shell_name)" in
    zsh)
      printf '%s\n' \
        "$HOME/.zshrc" \
        "$HOME/.bashrc" \
        "$HOME/.bash_profile" \
        "$HOME/.profile"
      return 0
      ;;
    bash)
      printf '%s\n' \
        "$HOME/.bashrc" \
        "$HOME/.bash_profile" \
        "$HOME/.profile" \
        "$HOME/.zshrc"
      return 0
      ;;
  esac

  case "$(uname_s)" in
    Darwin)
      printf '%s\n' \
        "$HOME/.zshrc" \
        "$HOME/.bash_profile" \
        "$HOME/.bashrc" \
        "$HOME/.profile"
      ;;
    Linux)
      printf '%s\n' \
        "$HOME/.bashrc" \
        "$HOME/.profile" \
        "$HOME/.bash_profile" \
        "$HOME/.zshrc"
      ;;
    *)
      printf '%s\n' \
        "$HOME/.bashrc" \
        "$HOME/.bash_profile" \
        "$HOME/.profile" \
        "$HOME/.zshrc"
      ;;
  esac
}

first_shell_rc_candidate() {
  shell_rc_candidates | sed -n '1p'
}

shell_single_quote() {
  printf "'%s'" "$(printf '%s' "$1" | sed "s/'/'\\\\''/g")"
}

print_path_hint() {
  local install_dir="$1"
  local rc_file

  rc_file="$(first_shell_rc_candidate)"

  echo ""
  echo "Add this directory to PATH:"
  echo "  echo 'export PATH=\"${install_dir}:\$PATH\"' >> ${rc_file}"
  echo "  source ${rc_file}"
}

path_is_configured() {
  case ":$PATH:" in
    *":$DOCDOT_BIN_DIR:"*)
      return 0
      ;;
    *)
      return 1
      ;;
  esac
}

ensure_path_in_shell_config() {
  local path_line
  local rc_file
  local rc_dir
  local marker_begin
  local marker_end

  path_line="export PATH=\"$DOCDOT_BIN_DIR:\$PATH\""
  marker_begin="# >>> docdot PATH >>>"
  marker_end="# <<< docdot PATH <<<"

  while IFS= read -r rc_file; do
    [ -n "$rc_file" ] || continue
    if [ -f "$rc_file" ]; then
      if grep -Fqx -- "$path_line" "$rc_file" 2>/dev/null; then
        printf '%s\n' "$rc_file"
        return 0
      fi

      if grep -Fqx -- "$marker_begin" "$rc_file" 2>/dev/null; then
        printf '%s\n' "$rc_file"
        return 0
      fi
    fi
  done <<EOF
$(shell_rc_candidates)
EOF

  while IFS= read -r rc_file; do
    [ -n "$rc_file" ] || continue
    rc_dir="$(dirname "$rc_file")"

    if [ -f "$rc_file" ]; then

      if [ ! -w "$rc_file" ]; then
        continue
      fi
    else
      if [ ! -w "$rc_dir" ]; then
        continue
      fi
      : > "$rc_file" || continue
    fi

    {
      printf '\n%s\n' "$marker_begin"
      printf '%s\n' "$path_line"
      printf '%s\n' "$marker_end"
    } >> "$rc_file" || continue

    printf '%s\n' "$rc_file"
    return 0
  done <<EOF
$(shell_rc_candidates)
EOF

  return 1
}

prepare_install_root() {
  step "Preparing install directory: $DOCDOT_BIN_DIR"
  mkdir -p "$DOCDOT_BIN_DIR"
}

maybe_install_pdf_skill() {
  local installed_path="$1"

  if [ "${DOCDOT_SKIP_SKILLS_INSTALL:-}" = "1" ]; then
    log "Skipping Hermes/OpenClaw/Claude Code/Codex skill replacement."
    return 0
  fi

  if [ -r /dev/tty ] && [ -w /dev/tty ]; then
    if ! "$installed_path" skills install < /dev/tty > /dev/tty 2>&1; then
      log "docdot skills install failed; run '$installed_path skills install' later."
    fi
    return 0
  fi

  log "Run '$installed_path skills install' to replace Hermes/OpenClaw/Claude Code/Codex PDF skills."
}

archive_url() {
  local base_url="$1"
  local platform="$2"
  local binary="$3"
  printf '%s/%s/%s-%s' "$base_url" "$DOCDOT_VERSION" "$binary" "$platform"
}

docdot_archive_url() {
  local platform="$1"
  archive_url "$DOCDOT_INSTALL_BASE_URL" "$platform" docdot
}

converter_archive_url() {
  local platform="$1"
  archive_url "$DOCDOT_CONVERTER_INSTALL_BASE_URL" "$platform" docdot-converter
}

install_binary() {
  local url="$1"
  local binary="$2"
  local download_path
  local target_path

  target_path="$DOCDOT_BIN_DIR/$binary"
  download_path="$(mktemp "$DOCDOT_BIN_DIR/.docdot.${binary}.XXXXXX")"

  cleanup() {
    rm -f "$download_path"
  }
  trap cleanup EXIT INT TERM HUP

  step "Downloading $binary from $url"
  if ! download_to_file "$url" "$download_path"; then
    die "Failed to download $binary binary: $url"
  fi

  step "Installing binary to $target_path"
  chmod 755 "$download_path"
  mv -f "$download_path" "$target_path"

  trap - EXIT INT TERM HUP
  cleanup

  printf '%s\n' "$target_path"
}

main() {
  local platform
  local url
  local installed_path
  local converter_url
  local converter_path
  local rc_file

  case "${1:-}" in
    -h | --help)
      usage
      exit 0
      ;;
    --skip-skills-install)
      DOCDOT_SKIP_SKILLS_INSTALL=1
      ;;
    "")
      ;;
    *)
      die "Unexpected arguments: $*"
      ;;
  esac

  setup_colors
  step "Starting docdot installation"
  step "Detecting platform"
  platform="$(detect_platform)"
  url="$(docdot_archive_url "$platform")"
  converter_url="$(converter_archive_url "$platform")"
  log "Resolved platform: $platform"

  prepare_install_root
  installed_path="$(install_binary "$url" docdot)"
  converter_path="$(install_binary "$converter_url" docdot-converter)"

  success "docdot installed to $installed_path"
  success "docdot-converter installed to $converter_path"

  if path_is_configured; then
    success "PATH already contains $DOCDOT_BIN_DIR"
  else
    print_path_hint "$DOCDOT_BIN_DIR"
    step "Updating shell PATH configuration"
    if rc_file="$(ensure_path_in_shell_config)"; then
      success "Added $DOCDOT_BIN_DIR to PATH in $rc_file"
      log "Run: source $rc_file"
    else
      warn "Could not update PATH automatically."
      rc_file="$(first_shell_rc_candidate)"
      warn "Run these commands to add docdot to PATH:"
      printf '  echo %s >> %s\n' "$(shell_single_quote "export PATH=\"$DOCDOT_BIN_DIR:\$PATH\"")" "$rc_file" >&2
      printf '  source %s\n' "$rc_file" >&2
    fi
  fi

  maybe_install_pdf_skill "$installed_path"
}

main "$@"
