#!/bin/sh
# setup — Dotfiles bootstrap for https://dev.pivoine.art/valknar/home
#
# Quick install:
#   curl https://dev.pivoine.art/valknar/home/raw/branch/main/bin/setup -sSf | sh
#
# Safe to re-run — all steps are idempotent.
#
# What this script does:
#   1. Re-execs itself with bash (curl|sh consumes stdin, so bash -c re-fetch is required)
#   2. Detects OS, installs git if missing — apt-get on Debian/Ubuntu, xcode-select on macOS
#   3. Installs zsh if missing, sets it as the default shell
#   4. Clones this dotfiles repo into ~ via HTTPS (or pulls if already present)
#   5. Runs arty deps — oh-my-zsh, p10k, nvm, rbenv, pyenv, zsh plugins
#   6. Installs arty zsh completion via: arty completion zsh --install
#   7. Prints next steps

# ─── Step 0: Re-exec with bash ────────────────────────────────────────────────
# curl URL | sh feeds the script on stdin. Once read, stdin is exhausted —
# `exec bash -s` would give bash nothing to interpret. The only reliable
# solution (used by Homebrew and rustup) is to re-download the script and
# hand it to `bash -c`. This costs one extra HTTP request but is correct.
if [ -z "${BASH_VERSION:-}" ]; then
  _SETUP_URL="https://dev.pivoine.art/valknar/home/raw/branch/main/bin/setup"
  if command -v curl >/dev/null 2>&1; then
    exec bash -c "$(curl -fsSL "$_SETUP_URL")" -- "$@"
  elif command -v wget >/dev/null 2>&1; then
    exec bash -c "$(wget -qO- "$_SETUP_URL")" -- "$@"
  else
    echo "[x] curl or wget is required. Please install one and retry." >&2
    exit 1
  fi
fi

# ─── Bash from here ───────────────────────────────────────────────────────────
set -euo pipefail

# ─── Constants ────────────────────────────────────────────────────────────────
readonly REPO_HTTPS="https://dev.pivoine.art/valknar/home.git"
readonly SETUP_URL="https://dev.pivoine.art/valknar/home/raw/branch/main/bin/setup"

# ─── Colors ───────────────────────────────────────────────────────────────────
# Matches arty's FORCE_COLOR convention: colors only when stdout is a terminal.
if [[ -t 1 && "${TERM:-}" != "dumb" ]]; then
  export FORCE_COLOR="${FORCE_COLOR:-1}"
fi
if [[ "${FORCE_COLOR:-0}" == "0" ]]; then
  RED='' GREEN='' YELLOW='' BLUE='' CYAN='' BOLD='' NC=''
else
  RED='\033[0;31m'
  GREEN='\033[0;32m'
  YELLOW='\033[1;33m'
  BLUE='\033[0;34m'
  CYAN='\033[0;36m'
  BOLD='\033[1m'
  NC='\033[0m'
fi

# ─── Logging ──────────────────────────────────────────────────────────────────
log_info()    { echo -e "${BLUE}[INFO]${NC} $1"; }
log_success() { echo -e "${GREEN}[ok]${NC} $1"; }
log_warn()    { echo -e "${YELLOW}[!]${NC} $1"; }
log_error()   { echo -e "${RED}[x]${NC} $1" >&2; }

step_header() {
  echo
  echo -e "${CYAN}${BOLD}══════════════════════════════════════════${NC}"
  echo -e "${CYAN}${BOLD}  $1${NC}"
  echo -e "${CYAN}${BOLD}══════════════════════════════════════════${NC}"
}

# ─── OS Detection ─────────────────────────────────────────────────────────────
OS="unknown"

detect_os() {
  local kernel
  kernel="$(uname -s | tr '[:upper:]' '[:lower:]')"
  case "$kernel" in
    darwin)
      OS="macos"
      ;;
    linux)
      if [[ -f /etc/os-release ]]; then
        local os_id
        os_id="$(. /etc/os-release && echo "${ID:-}")"
        case "$os_id" in
          debian|ubuntu|linuxmint|pop) OS="debian" ;;
          *) OS="linux" ;;
        esac
      else
        OS="linux"
      fi
      ;;
    *)
      OS="unknown"
      ;;
  esac
}

# ─── Step 1: Prerequisites ────────────────────────────────────────────────────
check_prerequisites() {
  step_header "Step 1 of 7 — Prerequisites"

  detect_os
  log_info "OS detected: ${BOLD}$OS${NC}"

  if command -v curl >/dev/null 2>&1; then
    log_success "curl $(curl --version | head -1 | awk '{print $2}')"
  elif command -v wget >/dev/null 2>&1; then
    log_success "wget $(wget --version 2>&1 | head -1 | awk '{print $3}')"
  else
    log_error "curl or wget is required."
    exit 1
  fi
}

# ─── Step 2: Ensure git ───────────────────────────────────────────────────────
ensure_git() {
  step_header "Step 2 of 7 — Git"

  if command -v git >/dev/null 2>&1; then
    log_success "git $(git --version | awk '{print $3}')"
    return 0
  fi

  log_warn "git not found — installing for OS: $OS"

  case "$OS" in
    debian)
      if ! command -v sudo >/dev/null 2>&1; then
        log_error "sudo is required to install git on Debian/Ubuntu."
        log_error "Run as root: apt-get install -y git — then re-run this script."
        exit 1
      fi
      sudo apt-get update -qq
      sudo apt-get install -y git
      log_success "git installed: $(git --version | awk '{print $3}')"
      ;;
    macos)
      # xcode-select --install shows a GUI dialog — it cannot run non-interactively.
      # We trigger it and exit, asking the user to re-run after the tools install.
      log_warn "git on macOS is provided by Xcode Command Line Tools."
      log_warn "A system dialog will appear — click 'Install' to proceed."
      xcode-select --install 2>/dev/null || true
      echo
      log_warn "After the tools finish installing, re-run:"
      log_warn "  curl $SETUP_URL -sSf | sh"
      exit 0
      ;;
    *)
      log_error "Cannot install git automatically on OS: $OS"
      log_error "Please install git manually, then re-run this script."
      exit 1
      ;;
  esac
}

# ─── Step 3: Ensure zsh ───────────────────────────────────────────────────────
ensure_zsh() {
  step_header "Step 3 of 7 — Zsh"

  if command -v zsh >/dev/null 2>&1; then
    log_success "zsh $(zsh --version | awk '{print $2}')"
  else
    log_warn "zsh not found — installing for OS: $OS"
    case "$OS" in
      debian)
        if ! command -v sudo >/dev/null 2>&1; then
          log_error "sudo is required to install zsh on Debian/Ubuntu."
          log_error "Run as root: apt-get install -y zsh — then re-run this script."
          exit 1
        fi
        sudo apt-get update -qq
        sudo apt-get install -y zsh
        log_success "zsh installed: $(zsh --version | awk '{print $2}')"
        ;;
      macos)
        if command -v brew >/dev/null 2>&1; then
          brew install zsh
          log_success "zsh installed: $(zsh --version | awk '{print $2}')"
        else
          log_warn "zsh not found and Homebrew is not available."
          log_warn "Install zsh manually: https://www.zsh.org"
        fi
        ;;
      *)
        log_warn "Cannot install zsh automatically on OS: $OS"
        log_warn "Please install zsh manually, then re-run this script."
        ;;
    esac
  fi

  # Set zsh as the default shell if it isn't already.
  local zsh_path
  zsh_path="$(command -v zsh 2>/dev/null || true)"
  if [[ -n "$zsh_path" && "$SHELL" != "$zsh_path" ]]; then
    log_info "Setting zsh as default shell..."
    if command -v chsh >/dev/null 2>&1; then
      # Add zsh to /etc/shells if missing (required by chsh).
      if ! grep -qx "$zsh_path" /etc/shells 2>/dev/null; then
        echo "$zsh_path" | sudo tee -a /etc/shells >/dev/null
      fi
      if sudo chsh -s "$zsh_path" "$USER" 2>/dev/null || chsh -s "$zsh_path" 2>/dev/null; then
        log_success "Default shell set to zsh (takes effect on next login)"
      else
        log_warn "Could not set default shell automatically."
        log_warn "Run manually: chsh -s $zsh_path"
      fi
    else
      log_warn "chsh not available — set your default shell manually: chsh -s $zsh_path"
    fi
  fi
}

# ─── Step 4: Clone or update dotfiles ─────────────────────────────────────────
setup_dotfiles() {
  step_header "Step 4 of 7 — Dotfiles"

  local is_git_repo=0
  local is_this_repo=0

  if git -C "$HOME" rev-parse --git-dir >/dev/null 2>&1; then
    is_git_repo=1
    local remote_url
    remote_url="$(git -C "$HOME" remote get-url origin 2>/dev/null || echo '')"
    if echo "$remote_url" | grep -q "dev.pivoine.art/valknar/home"; then
      is_this_repo=1
    fi
  fi

  # Idempotent update: repo already present and pointing to this remote → pull.
  if [[ -f "$HOME/arty.yml" && "$is_this_repo" == 1 ]]; then
    log_info "Dotfiles already present at $HOME"
    log_info "Pulling latest changes..."
    if ! git -C "$HOME" pull --ff-only 2>&1; then
      log_warn "Fast-forward pull failed — repo may have local divergence."
      log_warn "Inspect with: git -C ~ status"
      log_warn "Continuing with current state."
    else
      log_success "Dotfiles up to date"
    fi
    return 0
  fi

  # Fresh install: initialise ~ as a git repo.
  log_info "Initialising dotfiles repository in $HOME"
  log_info "Remote: $REPO_HTTPS"

  (
    cd "$HOME"
    git init

    if git remote get-url origin >/dev/null 2>&1; then
      log_warn "Replacing existing 'origin' remote (was: $(git remote get-url origin))"
      git remote remove origin
    fi

    git remote add origin "$REPO_HTTPS"
    log_info "Fetching repository..."
    git fetch --quiet

    # Force-checkout is intentional: this dotfiles repo uses an inverted
    # .gitignore (ignore everything, whitelist specific files), so only the
    # tracked dotfiles are overwritten — no other home directory files are touched.
    git checkout -f -t origin/main

    # Silence `git status` noise — the home directory has thousands of
    # untracked files that we deliberately do not track.
    git config status.showUntrackedFiles no
  )

  log_success "Dotfiles cloned into $HOME"
}

# ─── Step 5: Install dependencies via arty ────────────────────────────────────
install_deps() {
  step_header "Step 5 of 7 — Dependencies (arty deps)"

  local arty_bin="$HOME/bin/arty"

  if [[ ! -f "$arty_bin" ]]; then
    log_error "arty not found at $arty_bin"
    log_error "Step 3 (dotfiles clone) may have failed."
    exit 1
  fi

  if [[ ! -x "$arty_bin" ]]; then
    chmod +x "$arty_bin"
  fi

  log_info "Installing: oh-my-zsh, powerlevel10k, nvm, rbenv, pyenv, zsh plugins..."

  (
    cd "$HOME"
    "$arty_bin" deps
  )

  log_success "All dependencies installed"
}

# ─── Step 6: Install arty zsh completion ──────────────────────────────────────
install_completion() {
  step_header "Step 6 of 7 — Zsh completion"

  local arty_bin="$HOME/bin/arty"

  # Ensure tools that arty deps may have installed (yq, etc.) are on PATH.
  # arty deps runs in a subshell — its PATH exports don't survive back here.
  export PATH="$HOME/.local/bin:$HOME/go/bin:$PATH"

  # arty completion zsh --install writes to the first writable fpath dir,
  # defaulting to ~/.zsh/completions/_arty (which .zshenv/oh-my-zsh picks up).
  (cd "$HOME" && "$arty_bin" completion zsh --install) || true
  if [[ ! -f "$HOME/.zsh/completions/_arty" ]]; then
    log_warn "arty completion zsh --install failed — skipping."
  fi
}

# ─── Step 7: Post-install summary ─────────────────────────────────────────────
post_install() {
  step_header "Step 7 of 7 — Done"

  echo
  echo -e "${GREEN}${BOLD}Setup complete.${NC} Next steps:"
  echo
  echo -e "  ${CYAN}1.${NC} First time on this machine? Configure the Powerlevel10k prompt:"
  echo -e "       ${BOLD}p10k configure${NC}"
  echo
  echo -e "  ${CYAN}2.${NC} Generate an SSH key for git push access to dev.pivoine.art:"
  echo -e "       ${BOLD}arty ssh:keygen${NC}"
  echo -e "     Then add the public key at ${BLUE}https://dev.pivoine.art${NC}"
  echo
  echo -e "  ${CYAN}3.${NC} Switch the dotfiles remote from HTTPS to SSH (after key is set up):"
  echo -e "       ${BOLD}git -C ~ remote set-url origin ssh://git@dev.pivoine.art/valknar/home.git${NC}"
  echo
}

# ─── Main ─────────────────────────────────────────────────────────────────────
main() {
  echo
  echo -e "${BOLD}${CYAN}Valknar's dotfiles${NC} — ${BLUE}https://dev.pivoine.art/valknar/home${NC}"
  echo

  check_prerequisites  # Step 1
  ensure_git           # Step 2
  ensure_zsh           # Step 3
  setup_dotfiles       # Step 4
  install_deps         # Step 5
  install_completion   # Step 6
  post_install         # Step 7

  # Hand off to a zsh login shell immediately.
  # Read from /dev/tty so zsh gets the terminal, not the leftover pipe bytes
  # from the curl|sh pattern (which still has the tail of this script buffered).
  if command -v zsh >/dev/null 2>&1 && [[ -e /dev/tty ]]; then
    exec zsh -l </dev/tty
  fi
  echo -e "${YELLOW}[!]${NC} Start a new shell session: ${BOLD}exec zsh${NC}"
}

main "$@"
