#!/usr/bin/env bash

set -euo pipefail

# ------------------------------------------------------------
# Budibase install script
#
# Usage:
#   curl -fsSL https://install.budibase.com | bash
#
# Overrides (env vars):
#   PORT=8080 \
#   DATA_DIR=/srv/budibase/data \
#   BUDIBASE_IMAGE=budibase/budibase:v3.0.0 \
#   CONTAINER_NAME=budibase \
#   curl -fsSL https://install.budibase.com | bash
# ------------------------------------------------------------

# Defaults (override via env)
BUDIBASE_IMAGE="${BUDIBASE_IMAGE:-budibase/budibase:latest}"
CONTAINER_NAME="${CONTAINER_NAME:-budibase}"
DATA_DIR="${DATA_DIR:-${HOME}/budibase/data}"
PORT="${PORT:-10000}"

RED="\033[0;31m"
GREEN="\033[0;32m"
YELLOW="\033[1;33m"
NC="\033[0m"

log()  { echo -e "${GREEN}[Budibase]${NC} $1"; }
warn() { echo -e "${YELLOW}[Budibase]${NC} $1"; }
die()  { echo -e "${RED}[Budibase]${NC} $1"; exit 1; }

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

is_integer() {
  [[ "${1:-}" =~ ^[0-9]+$ ]]
}

port_available() {
  local port="$1"

  if command_exists lsof; then
    ! lsof -nP -iTCP:"${port}" -sTCP:LISTEN >/dev/null 2>&1
    return $?
  fi

  if command_exists ss; then
    ! ss -ltn 2>/dev/null | awk '{print $4}' | grep -E "[:.]${port}$" -q
    return $?
  fi

  if command_exists netstat; then
    ! netstat -an 2>/dev/null | grep -E "[\.:]${port}[[:space:]]" | grep -i LISTEN -q
    return $?
  fi

  # If we cannot detect port usage, allow install to continue
  return 0
}

normalize_data_dir() {
  local d="$1"
  if [[ "$d" == "~" || "$d" == "~/"* ]]; then
    d="${HOME}${d:1}"
  fi
  echo "$d"
}

preflight() {
  log "Starting Budibase installation..."

  if ! command_exists docker; then
    die "Docker is not installed. Install Docker first: https://docs.docker.com/get-docker/"
  fi

  if ! docker info >/dev/null 2>&1; then
    die "Docker daemon is not running. Start Docker and retry."
  fi

  if ! is_integer "${PORT}"; then
    die "PORT must be an integer. Got: ${PORT}"
  fi

  if (( PORT < 1 || PORT > 65535 )); then
    die "PORT must be between 1 and 65535. Got: ${PORT}"
  fi

  DATA_DIR="$(normalize_data_dir "${DATA_DIR}")"

  log "Configuration:"
  log "  Image:          ${BUDIBASE_IMAGE}"
  log "  Container name: ${CONTAINER_NAME}"
  log "  Host port:      ${PORT}"
  log "  Data dir:       ${DATA_DIR}"
}

ensure_data_dir() {
  log "Ensuring data directory exists at ${DATA_DIR}"

  mkdir -p "${DATA_DIR}"

  if [[ ! -w "${DATA_DIR}" ]]; then
    warn "Data directory is not writable: ${DATA_DIR}"
    warn "You may need to adjust permissions or choose a different DATA_DIR."
  fi
}

handle_existing_container() {
  if docker ps -a --format '{{.Names}}' | grep -qx "${CONTAINER_NAME}"; then
    warn "Existing container '${CONTAINER_NAME}' detected"

    local running
    running="$(docker inspect -f '{{.State.Running}}' "${CONTAINER_NAME}" 2>/dev/null || echo "false")"

    if [[ "${running}" == "true" ]]; then
      log "Budibase is already running"
      log "Access it at: http://localhost:${PORT}"
      exit 0
    fi

    warn "Removing stopped container '${CONTAINER_NAME}'"
    docker rm "${CONTAINER_NAME}" >/dev/null
  fi
}

check_port() {
  if ! port_available "${PORT}"; then
    die "Port ${PORT} is already in use. Choose another PORT, e.g.: PORT=8080 curl -fsSL https://install.budibase.com | bash"
  fi
}

pull_image() {
  log "Pulling image ${BUDIBASE_IMAGE}"
  docker pull "${BUDIBASE_IMAGE}" >/dev/null
}

run_container() {
  log "Starting container '${CONTAINER_NAME}'..."

  docker run -d \
    --name="${CONTAINER_NAME}" \
    -p "${PORT}:80" \
    -v "${DATA_DIR}:/data" \
    --restart unless-stopped \
    "${BUDIBASE_IMAGE}" >/dev/null
}

post_install() {
  log "Budibase successfully installed"
  log "---------------------------------------"
  log "UI:              http://localhost:${PORT}"
  log "Data directory:  ${DATA_DIR}"
  log "Container:       ${CONTAINER_NAME}"
  log "---------------------------------------"
  log "Useful commands:"
  log "  View logs:   docker logs -f ${CONTAINER_NAME}"
  log "  Stop:        docker stop ${CONTAINER_NAME}"
  log "  Start:       docker start ${CONTAINER_NAME}"
  log "  Remove:      docker rm -f ${CONTAINER_NAME}"
  log "Done."
}

main() {
  preflight
  ensure_data_dir
  check_port
  handle_existing_container
  pull_image
  run_container
  post_install
}

main "$@"
