#!/bin/bash
set -euo pipefail

# -----------------------------------------------
# Simple formatting helpers
# -----------------------------------------------
log()  { echo "[INFO]  $1"; }
ok()   { echo "[OK]    $1"; }
warn() { echo "[WARN]  $1"; }
err()  { echo "[ERROR] $1" >&2; exit 1; }

ask_yes_no() {
  local prompt="$1"
  local response
  read -rp "$prompt [y/N]: " response
  [[ "$response" =~ ^[Yy]$ ]]
}

# -----------------------------------------------
# Detect Docker privileges
# -----------------------------------------------
if ! docker info >/dev/null 2>&1; then
  warn "Docker requires elevated privileges."
  if ask_yes_no "Re-run this script with sudo?"; then
    echo "[INFO] Restarting with sudo..."
    exec sudo bash "$0" "$@"
  else
    err "Docker commands cannot run without sudo. Exiting."
  fi
fi

# -----------------------------------------------
# UTF-16 → UTF-8 tolerant reader
# -----------------------------------------------
normalize_to_utf8() {
  local input="$1"
  local tmp_utf8
  tmp_utf8=$(mktemp /tmp/provide-norm.XXXXXX)
  chmod 600 "$tmp_utf8"

  if file "$input" | grep -q "UTF-16"; then
    iconv -f UTF-16LE -t UTF-8//IGNORE "$input" > "$tmp_utf8" 2>/dev/null || cp "$input" "$tmp_utf8"
  else
    cp "$input" "$tmp_utf8"
  fi

  echo "$tmp_utf8"
}

# -----------------------------------------------
# Password update helper (for UTF-8 files)
# -----------------------------------------------
update_uac_password() {
  local file="$1"
  local new_pass="$2"
  local tmp_utf8
  tmp_utf8=$(normalize_to_utf8 "$file")

  if grep -Eq "^Password.*=" "$tmp_utf8"; then
    sed -i.bak -E "s/^Password.*=.*/Password=${new_pass}/" "$tmp_utf8"
  else
    echo "Password=${new_pass}" >> "$tmp_utf8"
  fi
  rm -f "$tmp_utf8.bak"
  mv "$tmp_utf8" "$file"
  chmod 600 "$file"
  ok "Password updated for $(basename "$file")"
}

# -----------------------------------------------
# Start setup
# -----------------------------------------------
log "Setting up ProVide Docker environment..."

ARCH=$(uname -m)
mkdir -p ./data/provide/accounts ./data/provide/certificates
ok "Data directories created."

# -----------------------------------------------
# Step 1: Download latest ProVide.exe if newer
# -----------------------------------------------
EXE_URL="https://download.provideserver.com/periodic/ProVide_x64-stable.exe"
EXE_PATH="./data/provide/ProVide.exe"

log "Checking for newer ProVide binary..."
REMOTE_DATE=$(curl -sI "$EXE_URL" | grep -i '^Last-Modified:' | sed 's/Last-Modified:[[:space:]]*//I' | tr -d '\r' || true)
REMOTE_TS=0
if [[ -n "$REMOTE_DATE" ]]; then
  if date -d "$REMOTE_DATE" +%s >/dev/null 2>&1; then
    REMOTE_TS=$(date -d "$REMOTE_DATE" +%s)
  elif date -j -f "%a, %d %b %Y %H:%M:%S %Z" "$REMOTE_DATE" +%s >/dev/null 2>&1; then
    REMOTE_TS=$(date -j -f "%a, %d %b %Y %H:%M:%S %Z" "$REMOTE_DATE" +%s)
  fi
fi

if [[ -f "$EXE_PATH" ]]; then
  LOCAL_TS=$(date -r "$EXE_PATH" +%s 2>/dev/null || stat -c %Y "$EXE_PATH")
  if [[ $REMOTE_TS -gt $LOCAL_TS ]]; then
    log "Remote version is newer — downloading update..."
    curl -fsSL "$EXE_URL" -o "$EXE_PATH" || err "Failed to download binary."
    chmod +x "$EXE_PATH"
    [[ -n "$REMOTE_DATE" ]] && touch -d "$REMOTE_DATE" "$EXE_PATH" 2>/dev/null || true
    ok "Updated binary to latest version."
  else
    ok "Local binary is up to date."
  fi
else
  log "No local binary found — downloading..."
  curl -fsSL "$EXE_URL" -o "$EXE_PATH" || err "Failed to download binary."
  chmod +x "$EXE_PATH"
  [[ -n "$REMOTE_DATE" ]] && touch -d "$REMOTE_DATE" "$EXE_PATH" 2>/dev/null || true
  ok "Downloaded latest binary."
fi

# -----------------------------------------------
# Step 2: Ensure Settings.ini and certificate section
# -----------------------------------------------
INI_FILE="./data/provide/Settings.ini"
CERT_DIR="./data/provide/certificates"
CERT_FILE="${CERT_DIR}/localhost.pfx"
CREATE_CERT=false

if [[ ! -f "$INI_FILE" ]]; then
  log "Creating new Settings.ini..."
  printf "[Current Certificate]\r\nlocalhost\r\n" > "$INI_FILE"
  CREATE_CERT=true
  ok "Created Settings.ini."
else
  log "Checking certificate section in Settings.ini..."
  TMP_UTF8=$(normalize_to_utf8 "$INI_FILE")

  if ! grep -qx '\[Current Certificate\]' "$TMP_UTF8"; then
    echo -e "\n[Current Certificate]\n\"localhost\"" >> "$TMP_UTF8"
    mv "$TMP_UTF8" "$INI_FILE"
    CREATE_CERT=true
    ok "Added [Current Certificate] section to Settings.ini."
  else
    ok "Settings.ini already contains [Current Certificate]."
  fi
  rm -f "$TMP_UTF8"
fi

# -----------------------------------------------
# Step 3: Certificate creation/recreation
# -----------------------------------------------
if [[ "$CREATE_CERT" == "true" ]] || [[ ! -f "$CERT_FILE" ]]; then
  log "Generating new self-signed TLS certificate..."
  openssl req -x509 -newkey rsa:2048 -sha256 -days 1095 \
    -nodes -subj "/CN=localhost" \
    -keyout "${CERT_DIR}/localhost.key" \
    -out "${CERT_DIR}/localhost.crt" >/dev/null 2>&1
  openssl pkcs12 -export \
    -out "${CERT_FILE}" \
    -inkey "${CERT_DIR}/localhost.key" \
    -in "${CERT_DIR}/localhost.crt" \
    -password pass: >/dev/null 2>&1
  rm -f "${CERT_DIR}/localhost.key" "${CERT_DIR}/localhost.crt"
  chmod 600 "${CERT_FILE}"
  ok "Certificate ready at: ${CERT_FILE}"
else
  ok "Existing certificate found — keeping it."
fi

# -----------------------------------------------
# Step 4: Admin account
# -----------------------------------------------
ADMIN_FILE="./data/provide/accounts/acc[Admin].uac"
if [[ ! -f "$ADMIN_FILE" ]]; then
  log "No Admin account found — creating one..."
  read -s -p "Enter Admin password for ProVide: " ADMIN_PASS; echo ""
  read -s -p "Confirm password: " ADMIN_CONFIRM; echo ""
  [[ "$ADMIN_PASS" != "$ADMIN_CONFIRM" ]] && err "Passwords do not match!"
  printf "Username=Admin\r\nPassword=%s\r\nRealname=I'm not psychic you know...\r\n[Admin]\r\n" "$ADMIN_PASS" > "$ADMIN_FILE"
  chmod 600 "$ADMIN_FILE"
  ok "Admin account created."
else
  warn "Admin account already exists."
  if ask_yes_no "Reset the Admin password?"; then
    read -s -p "Enter new Admin password: " ADMIN_PASS; echo ""
    read -s -p "Confirm password: " ADMIN_CONFIRM; echo ""
    [[ "$ADMIN_PASS" != "$ADMIN_CONFIRM" ]] && err "Passwords do not match!"
    update_uac_password "$ADMIN_FILE" "$ADMIN_PASS"
  else
    ok "Keeping existing Admin account."
  fi
fi

# -----------------------------------------------
# Step 5: Shutdown-tracker account
# -----------------------------------------------
UAC_FILE="./data/provide/accounts/acc[shutdown-tracker].uac"
SHUTDOWN_USER="shutdown-tracker"
ENV_FILE=".env"

get_env_value() {
  local key="$1"
  [[ -f "$ENV_FILE" ]] && grep -E "^${key}=" "$ENV_FILE" | cut -d'=' -f2- || echo ""
}

set_env_value() {
  local key="$1" value="$2"
  if grep -qE "^${key}=" "$ENV_FILE" 2>/dev/null; then
    sed -i.bak -E "s|^${key}=.*|${key}=${value}|" "$ENV_FILE"
  else
    echo "${key}=${value}" >> "$ENV_FILE"
  fi
  rm -f "${ENV_FILE}.bak"
}

if [[ ! -f "$UAC_FILE" ]]; then
  log "Creating shutdown account..."
  SHUTDOWN_PASS=$(openssl rand -base64 15 | tr -d '/+=' | cut -c1-20)
  printf "Username=%s\r\nPassword=%s\r\nRealname=ProVide Server Container Local Shutdown Account\r\n!Security - SpecifyAccessAllowList: True\r\n!Security - AccessAllowList: localhost\r\n[Admin]\r\n" "$SHUTDOWN_USER" "$SHUTDOWN_PASS" > "$UAC_FILE"
  chmod 600 "$UAC_FILE"
  ok "Shutdown account created."
else
  ok "Shutdown account already exists."
  CURRENT_PASS=$(get_env_value "PROVIDE_SHUTDOWN_PASS")
  if [[ -z "$CURRENT_PASS" ]]; then
    warn "Environment password missing — regenerating shutdown-tracker password..."
    SHUTDOWN_PASS=$(openssl rand -base64 15 | tr -d '/+=' | cut -c1-20)
    update_uac_password "$UAC_FILE" "$SHUTDOWN_PASS"
  else
    SHUTDOWN_PASS="$CURRENT_PASS"
  fi
fi

# -----------------------------------------------
# Step 6: Sync or create .env file
# -----------------------------------------------
log "Syncing environment file..."
if [[ ! -f "$ENV_FILE" ]]; then
  cat > "$ENV_FILE" <<EOF
PROVIDE_SHUTDOWN_USER=${SHUTDOWN_USER}
PROVIDE_SHUTDOWN_PASS=${SHUTDOWN_PASS}
PROVIDE_PORT=3145
EOF
  chmod 600 "$ENV_FILE"
  ok "Created new .env file."
else
  set_env_value "PROVIDE_SHUTDOWN_USER" "$SHUTDOWN_USER"
  set_env_value "PROVIDE_SHUTDOWN_PASS" "$SHUTDOWN_PASS"
  set_env_value "PROVIDE_PORT" "3145"
  ok "Updated .env file with current credentials."
fi

# -----------------------------------------------
# Step 7: Ensure QEMU/binfmt for ARM Macs
# -----------------------------------------------
if [[ "$ARCH" == "arm64" || "$ARCH" == "aarch64" ]]; then
  log "Preparing x86 emulation (QEMU/binfmt)..."
  docker run --privileged --rm tonistiigi/binfmt --install all >/dev/null 2>&1 \
    && ok "Multi-arch emulation ready." \
    || warn "Could not enable binfmt (already installed?)."
fi

# -----------------------------------------------
# Step 8: Build and start container
# -----------------------------------------------
log "Building and starting ProVide container..."
docker compose build --quiet >/dev/null 2>&1 || err "Docker build failed!"
docker compose up -d --quiet-pull >/dev/null 2>&1 || err "Container failed to start!"

# -----------------------------------------------
# Done
# -----------------------------------------------
ok "Setup complete."
echo ""
echo "Access web admin: https://localhost:8443"
echo "Check logs: docker compose logs -f"
echo ""
