#!/usr/bin/env bash
# Rehydrate the code-server container with the dev tooling Claude needs.
# Run from the Docker host as root:
#
#   docker exec -u root <container-name> bash /config/workspace/codeserver-setup/install.sh
#
# Idempotent: safe to re-run after every image upgrade or container redeploy.
# Targets Ubuntu 24.04 (noble) inside the linuxserver/code-server image.

set -euo pipefail

# ---------------------------------------------------------------------------
# Preflight
# ---------------------------------------------------------------------------

if [ "$(id -u)" -ne 0 ]; then
    cat >&2 <<EOF
ERROR: this script must run as root inside the container.
Invoke it from the Docker host with:

    docker exec -u root <container-name> bash $0
EOF
    exit 1
fi

if ! grep -q "Ubuntu 24.04" /etc/os-release 2>/dev/null; then
    echo "WARN: expected Ubuntu 24.04 (noble); proceeding anyway." >&2
fi

log() { printf '\n\033[1;36m[setup]\033[0m %s\n' "$*"; }

export DEBIAN_FRONTEND=noninteractive

# ---------------------------------------------------------------------------
# apt base
# ---------------------------------------------------------------------------

log "Refreshing apt indexes"
apt-get update -qq

log "Installing base utilities"
apt-get install -y --no-install-recommends \
    ca-certificates \
    curl \
    jq \
    unzip \
    wget

# ---------------------------------------------------------------------------
# PHP 8.3 CLI + extensions (matching Ubuntu 24.04 stock)
# ---------------------------------------------------------------------------

log "Installing PHP 8.3 CLI and common extensions"
apt-get install -y --no-install-recommends \
    php8.3-cli \
    php8.3-common \
    php8.3-curl \
    php8.3-gd \
    php8.3-intl \
    php8.3-mbstring \
    php8.3-mysql \
    php8.3-opcache \
    php8.3-xml \
    php8.3-zip

# ---------------------------------------------------------------------------
# Composer (official installer, pinned to /usr/local/bin)
# ---------------------------------------------------------------------------

if ! command -v composer >/dev/null 2>&1; then
    log "Installing Composer"
    php -r "copy('https://getcomposer.org/installer', '/tmp/composer-setup.php');"
    EXPECTED_SIG="$(curl -fsSL https://composer.github.io/installer.sig)"
    ACTUAL_SIG="$(php -r "echo hash_file('sha384', '/tmp/composer-setup.php');")"
    if [ "$EXPECTED_SIG" != "$ACTUAL_SIG" ]; then
        echo "ERROR: composer installer signature mismatch — aborting." >&2
        rm -f /tmp/composer-setup.php
        exit 1
    fi
    php /tmp/composer-setup.php --install-dir=/usr/local/bin --filename=composer --quiet
    rm -f /tmp/composer-setup.php
else
    log "Composer already installed — skipping"
fi

# ---------------------------------------------------------------------------
# MariaDB client (talks to host MariaDB over TCP or socket)
# ---------------------------------------------------------------------------

log "Installing MariaDB client"
apt-get install -y --no-install-recommends mariadb-client

# ---------------------------------------------------------------------------
# Search / file utilities
# ---------------------------------------------------------------------------

log "Installing ripgrep, fd-find, shellcheck"
apt-get install -y --no-install-recommends \
    ripgrep \
    fd-find \
    shellcheck

# Debian/Ubuntu ship fd-find's binary as 'fdfind' — symlink to 'fd' for muscle memory.
if [ ! -e /usr/local/bin/fd ] && command -v fdfind >/dev/null 2>&1; then
    ln -s "$(command -v fdfind)" /usr/local/bin/fd
fi

# ---------------------------------------------------------------------------
# PHP static analysis (PHARs in /usr/local/bin — no per-user composer setup)
# ---------------------------------------------------------------------------

install_phar() {
    local name="$1" url="$2" dest="/usr/local/bin/$1"
    if [ ! -x "$dest" ]; then
        log "Installing $name"
        curl -fsSL "$url" -o "$dest"
        chmod +x "$dest"
    else
        log "$name already installed — skipping"
    fi
}

install_phar phpstan https://github.com/phpstan/phpstan/releases/latest/download/phpstan.phar
install_phar phpcs   https://github.com/PHPCSStandards/PHP_CodeSniffer/releases/latest/download/phpcs.phar
install_phar phpcbf  https://github.com/PHPCSStandards/PHP_CodeSniffer/releases/latest/download/phpcbf.phar

# ---------------------------------------------------------------------------
# Node.js 20 LTS + esbuild
# ---------------------------------------------------------------------------
# The portal repo ships hand-maintained *.min.js / *.nomin.js pairs (no build
# pipeline). Node + esbuild let us regenerate the minified files from source
# (portal/build-min.js) and syntax-check JS (portal/check-syntax.js) instead of
# editing minified one-liners by hand.

if ! command -v node >/dev/null 2>&1; then
    log "Installing Node.js 20 LTS (NodeSource)"
    curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
    apt-get install -y --no-install-recommends nodejs
else
    log "Node.js already installed — skipping"
fi

# esbuild as a global CLI (matches the global-PHAR philosophy above — no
# per-project node_modules required for the build/check scripts to run).
if ! command -v esbuild >/dev/null 2>&1; then
    log "Installing esbuild (global)"
    npm install -g esbuild
else
    log "esbuild already installed — skipping"
fi

# ---------------------------------------------------------------------------
# Group membership: abc + www-data
# ---------------------------------------------------------------------------
# The web server (host LAMP) writes into bind-mounted dirs as www-data.
# Adding abc to the www-data group lets the editor user modify those files.
# Takes effect after the next container restart.

if id abc >/dev/null 2>&1 && getent group www-data >/dev/null 2>&1; then
    if ! id -nG abc | tr ' ' '\n' | grep -qx www-data; then
        log "Adding abc to www-data group"
        usermod -aG www-data abc
    else
        log "abc already in www-data group — skipping"
    fi
fi

# ---------------------------------------------------------------------------
# Evolution repo fixups
# ---------------------------------------------------------------------------
# `evolution/companies` is git-ignored and points at host-shared customer data
# (mounted at /var/www/shared/companies on the LAMP host). Recreate it if a
# fresh checkout or pull removed it.

EVO_ROOT="/config/workspace/evolution"
COMPANIES_LINK="$EVO_ROOT/companies"
if [ -d "$EVO_ROOT" ] && [ ! -L "$COMPANIES_LINK" ] && [ ! -e "$COMPANIES_LINK" ]; then
    log "Recreating evolution/companies symlink"
    ln -s /var/www/shared/companies "$COMPANIES_LINK"
    chown -h abc:www-data "$COMPANIES_LINK"
fi

# ---------------------------------------------------------------------------
# Claude memory persistence
# ---------------------------------------------------------------------------
# Claude's cross-session memory lives at
#   /config/.claude/projects/-config-workspace/memory/
# which sits outside the workspace git repos (so it survives branch switches).
# To also survive container redeploys, we keep a seed/backup copy alongside this
# script (codeserver-setup/ is a plain dir on the persistent /config volume, not
# a git repo). On each run we restore any memory files missing from the live
# dir, then refresh the backup from live so the seed stays current.

MEMORY_DIR="/config/.claude/projects/-config-workspace/memory"
MEMORY_SEED="$(dirname "$0")/memory-seed"

log "Syncing Claude memory (live <-> seed backup)"
mkdir -p "$MEMORY_DIR"

# Restore: copy seed files that are missing live (never clobber a live edit).
if [ -d "$MEMORY_SEED" ]; then
    cp -a --update=none "$MEMORY_SEED"/. "$MEMORY_DIR"/ 2>/dev/null || true
fi

# Backup: refresh the seed from the live dir so it reflects the latest memory.
if [ -n "$(ls -A "$MEMORY_DIR" 2>/dev/null)" ]; then
    mkdir -p "$MEMORY_SEED"
    cp -a "$MEMORY_DIR"/. "$MEMORY_SEED"/ 2>/dev/null || true
fi
chown -R abc:abc "$MEMORY_DIR" "$MEMORY_SEED" 2>/dev/null || true

# ---------------------------------------------------------------------------
# Cleanup
# ---------------------------------------------------------------------------

log "Cleaning apt caches"
apt-get clean
rm -rf /var/lib/apt/lists/*

# ---------------------------------------------------------------------------
# Verification — print versions of everything we just installed
# ---------------------------------------------------------------------------

log "Installed versions:"
printf '  %-11s %s\n' "php"        "$(php -v 2>/dev/null | head -1 || echo MISSING)"
printf '  %-11s %s\n' "composer"   "$(composer --version 2>/dev/null || echo MISSING)"
printf '  %-11s %s\n' "mariadb"    "$(mariadb --version 2>/dev/null || echo MISSING)"
printf '  %-11s %s\n' "curl"       "$(curl --version 2>/dev/null | head -1 || echo MISSING)"
printf '  %-11s %s\n' "jq"         "$(jq --version 2>/dev/null || echo MISSING)"
printf '  %-11s %s\n' "rg"         "$(rg --version 2>/dev/null | head -1 || echo MISSING)"
printf '  %-11s %s\n' "fd"         "$(fd --version 2>/dev/null || echo MISSING)"
printf '  %-11s %s\n' "shellcheck" "$(shellcheck --version 2>/dev/null | awk '/^version:/ {print $2}' || echo MISSING)"
printf '  %-11s %s\n' "phpstan"    "$(phpstan --version 2>/dev/null || echo MISSING)"
printf '  %-11s %s\n' "phpcs"      "$(phpcs --version 2>/dev/null || echo MISSING)"
printf '  %-11s %s\n' "node"       "$(node --version 2>/dev/null || echo MISSING)"
printf '  %-11s %s\n' "npm"        "$(npm --version 2>/dev/null || echo MISSING)"
printf '  %-11s %s\n' "esbuild"    "$(esbuild --version 2>/dev/null || echo MISSING)"

log "Done."
