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

ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$ROOT_DIR"

APP_ENV_FILE="$ROOT_DIR/.env"
APP_EXAMPLE_FILE="$ROOT_DIR/.env.example"
SKIP_NPM_INSTALL="${SKIP_NPM_INSTALL:-false}"

log() {
  printf "\n[%s] %s\n" "$(date '+%H:%M:%S')" "$1"
}

warn() {
  printf "\n[WARN] %s\n" "$1"
}

fail() {
  printf "\n[ERROR] %s\n" "$1"
  exit 1
}

ensure_not_root_required() {
  [[ "$(uname -s)" == "Linux" ]] || fail "This installer is intended for Linux/cPanel hosts."
}

ensure_node_18() {
  command -v node >/dev/null 2>&1 || fail "Node.js 18.x must be enabled in cPanel first."
  command -v npm >/dev/null 2>&1 || fail "npm must be available in your cPanel Node.js environment."
  local major
  major="$(node -p "process.versions.node.split('.')[0]")"
  [[ "$major" == "18" ]] || fail "Current Node.js version is $(node -v). cPanel installer requires Node.js 18.x."
  log "Using Node.js $(node -v) and npm $(npm -v)"
}

prepare_env() {
  [[ -f "$APP_EXAMPLE_FILE" ]] || fail ".env.example file is missing."
  log "Preparing .env"
  node scripts/setup.js
}

extract_env_json() {
  node - <<'NODE'
const fs = require("fs");
const path = require("path");
const dotenv = require("dotenv");
const envPath = path.resolve(process.cwd(), ".env");
const parsed = dotenv.parse(fs.readFileSync(envPath));
const url = new URL((parsed.DATABASE_URL || "").replace(/^"|"$/g, ""));
const output = {
  cpanelMode: (parsed.CPANEL_MODE || "false") === "true",
  cpanelAutoDb: (parsed.CPANEL_AUTO_DB || "false") === "true",
  cpanelDbBasename: parsed.CPANEL_DB_BASENAME || "minecraft",
  cpanelDbUserBasename: parsed.CPANEL_DB_USER_BASENAME || "mcsite",
  cpanelDbPassword: parsed.CPANEL_DB_PASSWORD || "",
  cpanelAppEntry: parsed.CPANEL_APP_ENTRY || "app.js",
  databaseUrl: (parsed.DATABASE_URL || "").replace(/^"|"$/g, ""),
  dbName: url.pathname.replace(/^\//, ""),
  dbUser: decodeURIComponent(url.username || ""),
  dbPassword: decodeURIComponent(url.password || ""),
  dbHost: url.hostname || "localhost",
  dbPort: Number(url.port || 3306),
  appUrl: parsed.APP_URL || ""
};
process.stdout.write(JSON.stringify(output));
NODE
}

cpanel_prefix() {
  if [[ -n "${CPANEL_ACCOUNT:-}" ]]; then
    printf "%s" "$CPANEL_ACCOUNT"
  elif [[ -n "${USER:-}" ]]; then
    printf "%s" "$USER"
  else
    whoami
  fi
}

normalize_cpanel_name() {
  local prefix="$1"
  local base="$2"
  local max_base_length="$3"
  local safe_base
  safe_base="$(printf "%s" "$base" | tr '[:upper:]' '[:lower:]' | tr -cd 'a-z0-9_')"
  safe_base="${safe_base:0:$max_base_length}"
  printf "%s_%s" "$prefix" "$safe_base"
}

set_env_value() {
  local key="$1"
  local value="$2"
  local escaped
  escaped="$(printf '%s' "$value" | sed -e 's/[\/&]/\\&/g')"
  if grep -q "^${key}=" "$APP_ENV_FILE"; then
    sed -i.bak "s/^${key}=.*/${key}=${escaped}/" "$APP_ENV_FILE"
  else
    printf "\n%s=%s\n" "$key" "$value" >> "$APP_ENV_FILE"
  fi
}

create_database_with_uapi() {
  local db_name="$1"
  local db_user="$2"
  local db_password="$3"

  command -v uapi >/dev/null 2>&1 || return 1

  log "Creating cPanel database via uapi"
  uapi --output=jsonpretty Mysql create_database "name=${db_name}" >/dev/null
  uapi --output=jsonpretty Mysql create_user "name=${db_user}" "password=${db_password}" >/dev/null
  uapi --output=jsonpretty Mysql set_privileges_on_database "user=${db_user}" "database=${db_name}" "privileges=ALL PRIVILEGES" >/dev/null
}

maybe_bootstrap_cpanel_database() {
  local env_json prefix db_name db_user db_password db_host db_port database_url cpanel_mode cpanel_auto_db
  env_json="$(extract_env_json)"
  cpanel_mode="$(node -e "const d=JSON.parse(process.argv[1]); console.log(d.cpanelMode);" "$env_json")"
  cpanel_auto_db="$(node -e "const d=JSON.parse(process.argv[1]); console.log(d.cpanelAutoDb);" "$env_json")"

  if [[ "$cpanel_mode" != "true" ]]; then
    warn "CPANEL_MODE is false. Enabling cPanel-safe defaults anyway."
    set_env_value "CPANEL_MODE" "true"
  fi

  if [[ "$cpanel_auto_db" != "true" ]]; then
    warn "CPANEL_AUTO_DB=false. Database creation is skipped; existing DATABASE_URL will be used."
    return
  fi

  prefix="$(cpanel_prefix)"
  db_name="$(normalize_cpanel_name "$prefix" "$(node -e "const d=JSON.parse(process.argv[1]); console.log(d.cpanelDbBasename);" "$env_json")" 48)"
  db_user="$(normalize_cpanel_name "$prefix" "$(node -e "const d=JSON.parse(process.argv[1]); console.log(d.cpanelDbUserBasename);" "$env_json")" 16)"
  db_password="$(node -e "const d=JSON.parse(process.argv[1]); console.log(d.cpanelDbPassword);" "$env_json")"
  db_host="$(node -e "const d=JSON.parse(process.argv[1]); console.log(d.dbHost);" "$env_json")"
  db_port="$(node -e "const d=JSON.parse(process.argv[1]); console.log(d.dbPort);" "$env_json")"

  if [[ -z "$db_password" ]]; then
    db_password="$(node -e "console.log(require('crypto').randomBytes(18).toString('hex'))")"
    set_env_value "CPANEL_DB_PASSWORD" "$db_password"
  fi

  create_database_with_uapi "$db_name" "$db_user" "$db_password" || fail "uapi database creation failed. Disable CPANEL_AUTO_DB and create DB manually, or ensure uapi is available."

  database_url="mysql://${db_user}:${db_password}@${db_host}:${db_port}/${db_name}"
  set_env_value "DATABASE_URL" "\"${database_url}\""
  log "cPanel database configured: ${db_name}"
}

install_dependencies() {
  if [[ "$SKIP_NPM_INSTALL" == "true" ]]; then
    warn "Skipping npm install because SKIP_NPM_INSTALL=true."
    return
  fi
  log "Installing Node.js dependencies"
  npm install --production=false
}

run_checks_and_bootstrap() {
  log "Checking .env"
  node scripts/check-env.js
  log "Checking database connection"
  node scripts/init-database.js
  log "Running Prisma migrations"
  npx prisma migrate deploy
  log "Running seed"
  node prisma/seed.js
  log "Ensuring superadmin account exists"
  node scripts/create-admin.js
}

print_cpanel_finish_notes() {
  local app_entry
  app_entry="$(grep '^CPANEL_APP_ENTRY=' "$APP_ENV_FILE" | head -n1 | cut -d= -f2-)"
  app_entry="${app_entry:-app.js}"
  log "cPanel installation finished"
  cat <<EOF

Next steps inside cPanel:
1. Open "Setup Node.js App"
2. Set application root to this project directory
3. Set application startup file to: ${app_entry}
4. Set application mode to: production
5. Add environment variables from .env if your host requires them in the UI
6. Run "npm install" from the app interface only if your host expects it there
7. Restart the Node.js app from cPanel

Health check:
  ${ROOT_DIR}
  URL: \$(grep '^APP_URL=' .env | cut -d= -f2-)/api/health

EOF
}

main() {
  ensure_not_root_required
  ensure_node_18
  prepare_env
  maybe_bootstrap_cpanel_database
  install_dependencies
  run_checks_and_bootstrap
  print_cpanel_finish_notes
}

main "$@"
