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

KAGEOS_IMAGE="${KAGEOS_IMAGE:-docker.io/qiayanai/kageos:latest}"
KAGEOS_CONTAINER_NAME="${KAGEOS_CONTAINER_NAME:-kageos}"
KAGEOS_VOLUME="${KAGEOS_VOLUME:-kageos-data}"
KAGEOS_ENGINE="${KAGEOS_ENGINE:-auto}"
KAGEOS_PORT="${KAGEOS_PORT:-auto}"
KAGEOS_BASE_URL="${KAGEOS_BASE_URL:-}"
KAGEOS_INSTALL_ENGINE="${KAGEOS_INSTALL_ENGINE:-auto}"
KAGEOS_START_TIMEOUT="${KAGEOS_START_TIMEOUT:-1200}"
KAGEOS_AIO_PRINT_SECRETS="${KAGEOS_AIO_PRINT_SECRETS:-1}"
KAGEOS_FORCE="${KAGEOS_FORCE:-0}"
KAGEOS_DRY_RUN="${KAGEOS_DRY_RUN:-0}"

ENGINE=""
ENGINE_CMD=()
SELECTED_PORT=""
BASE_URL=""

usage() {
  cat <<'EOF'
kageos local trial installer

Usage:
  curl -fsSL https://kageos.com/install.sh | bash
  curl -fsSL https://kageos.com/install.sh | bash -s -- --port 8080
  curl -fsSL https://kageos.com/install.sh | bash -s -- --base-url http://192.168.1.100:8080

What it does:
  - Uses Podman first, matching the kageos local runtime model.
  - Initializes and starts a Podman machine on macOS when needed.
  - On Linux, installs Podman packages automatically when possible.
  - Can use Docker as a compatibility fallback with --engine docker.
  - Pulls and runs docker.io/qiayanai/kageos as a single all-in-one container.
  - Creates a persistent Podman/Docker volume named kageos-data.
  - Prints the access URL and initial system password when ready.
  - Installs a small "kageos" helper command when /usr/local/bin is writable via sudo.

Options:
  --base-url URL       Browser-facing URL. Defaults to http://localhost or http://localhost:PORT.
  --port PORT          Host port to expose. Defaults to 80 when free, otherwise 8080+.
  --image IMAGE        Container image. Defaults to docker.io/qiayanai/kageos:latest.
  --version VERSION    Shortcut for docker.io/qiayanai/kageos:VERSION.
  --name NAME          Container name. Defaults to kageos.
  --volume NAME        Persistent volume name. Defaults to kageos-data.
  --engine ENGINE      auto, docker, or podman. Defaults to auto.
  --no-install-engine  Do not install Podman automatically.
  --no-install-runtime Same as --no-install-engine.
  --force              Recreate the container, preserving the data volume.
  --dry-run            Print the selected engine, port, and URL, then exit.
  --help               Show this help.

Examples:
  # Local machine or Ubuntu VM
  curl -fsSL https://kageos.com/install.sh | bash

  # LAN access from another machine
  curl -fsSL https://kageos.com/install.sh | bash -s -- \
    --base-url http://192.168.1.100:8080 --port 8080

  # Pin a released version
  curl -fsSL https://kageos.com/install.sh | bash -s -- --version 0.2.0

  # Docker compatibility fallback
  curl -fsSL https://kageos.com/install.sh | bash -s -- --engine docker --port 8080

Environment:
  KAGEOS_IMAGE, KAGEOS_BASE_URL, KAGEOS_PORT, KAGEOS_ENGINE,
  KAGEOS_CONTAINER_NAME, KAGEOS_VOLUME, KAGEOS_INSTALL_ENGINE,
  KAGEOS_START_TIMEOUT, KAGEOS_AIO_PRINT_SECRETS.
EOF
}

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

warn() {
  printf '\033[1;33mWARN:\033[0m %s\n' "$*" >&2
}

die() {
  printf '\033[1;31mERROR:\033[0m %s\n' "$*" >&2
  exit 1
}

need_value() {
  local option="$1"
  shift
  [[ $# -gt 0 && -n "${1:-}" ]] || die "$option requires a value"
}

while [[ $# -gt 0 ]]; do
  case "$1" in
    --base-url)
      shift
      need_value "--base-url" "$@"
      KAGEOS_BASE_URL="$1"
      ;;
    --port)
      shift
      need_value "--port" "$@"
      KAGEOS_PORT="$1"
      ;;
    --image)
      shift
      need_value "--image" "$@"
      KAGEOS_IMAGE="$1"
      ;;
    --version)
      shift
      need_value "--version" "$@"
      KAGEOS_IMAGE="docker.io/qiayanai/kageos:$1"
      ;;
    --name)
      shift
      need_value "--name" "$@"
      KAGEOS_CONTAINER_NAME="$1"
      ;;
    --volume)
      shift
      need_value "--volume" "$@"
      KAGEOS_VOLUME="$1"
      ;;
    --engine)
      shift
      need_value "--engine" "$@"
      KAGEOS_ENGINE="$1"
      ;;
    --no-install-engine|--no-install-runtime)
      KAGEOS_INSTALL_ENGINE="never"
      ;;
    --force)
      KAGEOS_FORCE="1"
      ;;
    --dry-run)
      KAGEOS_DRY_RUN="1"
      ;;
    --help|-h)
      usage
      exit 0
      ;;
    *)
      die "unknown option: $1"
      ;;
  esac
  shift
done

case "$KAGEOS_ENGINE" in
  auto|docker|podman) ;;
  *) die "--engine must be auto, docker, or podman" ;;
esac

if [[ "$KAGEOS_PORT" != "auto" && ! "$KAGEOS_PORT" =~ ^[0-9]+$ ]]; then
  die "--port must be a number"
fi

if [[ ! "$KAGEOS_START_TIMEOUT" =~ ^[0-9]+$ ]]; then
  die "KAGEOS_START_TIMEOUT must be a number"
fi

root_cmd() {
  if [[ "$(id -u)" -eq 0 ]]; then
    "$@"
    return
  fi
  command -v sudo >/dev/null 2>&1 || die "sudo is required for this step. Install Podman manually, then rerun this installer."
  sudo "$@"
}

is_linux() {
  [[ "$(uname -s | tr '[:upper:]' '[:lower:]')" == "linux" ]]
}

is_macos() {
  [[ "$(uname -s | tr '[:upper:]' '[:lower:]')" == "darwin" ]]
}

linux_id_like() {
  [[ -r /etc/os-release ]] || return 1
  . /etc/os-release
  printf '%s %s\n' "${ID:-}" "${ID_LIKE:-}"
}

install_podman_engine() {
  [[ "$KAGEOS_INSTALL_ENGINE" != "never" ]] || return 1
  is_linux || return 1

  local ids
  ids="$(linux_id_like || true)"
  log "Installing Podman where available"
  if [[ "$ids" == *"ubuntu"* || "$ids" == *"debian"* ]]; then
    root_cmd env DEBIAN_FRONTEND=noninteractive apt-get update
    root_cmd env DEBIAN_FRONTEND=noninteractive apt-get install -y podman uidmap slirp4netns fuse-overlayfs
  elif command -v dnf >/dev/null 2>&1; then
    root_cmd dnf install -y podman slirp4netns fuse-overlayfs
  elif command -v yum >/dev/null 2>&1; then
    root_cmd yum install -y podman slirp4netns fuse-overlayfs
  elif command -v zypper >/dev/null 2>&1; then
    root_cmd zypper --non-interactive install podman slirp4netns fuse-overlayfs
  elif command -v apk >/dev/null 2>&1; then
    root_cmd apk add --no-cache podman fuse-overlayfs slirp4netns
  else
    return 1
  fi
}

print_podman_desktop_instructions() {
  cat >&2 <<'EOF'

Podman Desktop is required for the kageos local desktop runtime.

Recommended setup:
  1. Install Podman Desktop:
       https://podman-desktop.io/downloads
  2. Open Podman Desktop.
  3. Run the onboarding flow to install Podman and create/start a Podman machine.
  4. Rerun:
       curl -fsSL https://kageos.com/install.sh | bash -s -- --port 8080

macOS shortcut when you intentionally use Homebrew:
  brew install --cask podman-desktop

EOF
}

ensure_podman_machine() {
  local candidate="$1"

  "$candidate" machine list >/tmp/kageos-podman-machine-list.log 2>&1 || return 1

  if "$candidate" machine inspect >/tmp/kageos-podman-machine-inspect.log 2>&1; then
    "$candidate" machine start >/tmp/kageos-podman-machine-start.log 2>&1 || true
  else
    log "Creating Podman machine"
    "$candidate" machine init >/tmp/kageos-podman-machine-init.log 2>&1 || return 1
    "$candidate" machine start >/tmp/kageos-podman-machine-start.log 2>&1 || return 1
  fi

  "$candidate" info >/tmp/kageos-podman-info.log 2>&1
}

try_engine() {
  local candidate="$1"
  command -v "$candidate" >/dev/null 2>&1 || return 1

  if "$candidate" info >/tmp/kageos-${candidate}-info.log 2>&1; then
    ENGINE="$candidate"
    ENGINE_CMD=("$candidate")
    return 0
  fi

  if [[ "$candidate" == "podman" ]] && ensure_podman_machine "$candidate"; then
    ENGINE="$candidate"
    ENGINE_CMD=("$candidate")
    return 0
  fi

  if [[ "$(id -u)" -ne 0 ]] && command -v sudo >/dev/null 2>&1; then
    if sudo -n "$candidate" info >/tmp/kageos-${candidate}-info.log 2>&1; then
      ENGINE="$candidate"
      ENGINE_CMD=(sudo "$candidate")
      return 0
    fi
  fi

  if [[ "$candidate" == "podman" ]] && command -v sudo >/dev/null 2>&1; then
    if sudo -n podman info >/tmp/kageos-podman-info.log 2>&1; then
      ENGINE="$candidate"
      ENGINE_CMD=(sudo "$candidate")
      return 0
    fi
  fi

  return 1
}

try_existing_engine() {
  local candidate="$1"
  command -v "$candidate" >/dev/null 2>&1 || return 1

  if "$candidate" container inspect "$KAGEOS_CONTAINER_NAME" >/dev/null 2>&1; then
    try_engine "$candidate"
    return
  fi

  if [[ "$(id -u)" -ne 0 ]] && command -v sudo >/dev/null 2>&1; then
    if sudo -n "$candidate" container inspect "$KAGEOS_CONTAINER_NAME" >/dev/null 2>&1; then
      try_engine "$candidate"
      return
    fi
  fi

  return 1
}

select_engine() {
  if [[ "$KAGEOS_ENGINE" != "auto" ]]; then
    if ! try_engine "$KAGEOS_ENGINE" && [[ "$(id -u)" -ne 0 ]] && command -v sudo >/dev/null 2>&1; then
      log "Checking ${KAGEOS_ENGINE} with sudo"
      root_cmd true
    fi
    try_engine "$KAGEOS_ENGINE" || die "$KAGEOS_ENGINE is not installed or not usable. Check /tmp/kageos-${KAGEOS_ENGINE}-info.log if it exists."
    log "Using container engine: ${ENGINE}"
    return
  fi

  if try_existing_engine podman; then
    log "Using existing container engine: podman"
    return
  fi

  if try_existing_engine docker; then
    log "Using existing container engine: docker"
    return
  fi

  if try_engine podman; then
    log "Using container engine: podman"
    return
  fi

  if command -v podman >/dev/null 2>&1; then
    warn "Podman is installed but not usable. Check /tmp/kageos-podman-info.log and /tmp/kageos-podman-machine-start.log."
    if [[ "$(id -u)" -ne 0 ]] && command -v sudo >/dev/null 2>&1; then
      log "Checking Podman with sudo"
      root_cmd true
      if try_engine podman; then
        log "Using container engine: podman"
        return
      fi
    fi
  fi

  if install_podman_engine && try_engine podman; then
    log "Using container engine: podman"
    return
  fi

  if is_macos; then
    print_podman_desktop_instructions
    die "No usable Podman found. Install Podman Desktop, complete onboarding, then rerun this installer."
  fi

  if command -v docker >/dev/null 2>&1; then
    warn "Docker was detected but is not used automatically. Rerun with --engine docker to use the compatibility fallback."
  fi

  die "No usable Podman found. Install Podman Desktop/Podman, then rerun this installer."
}

engine() {
  "${ENGINE_CMD[@]}" "$@"
}

container_exists() {
  engine container inspect "$KAGEOS_CONTAINER_NAME" >/dev/null 2>&1
}

container_running() {
  [[ "$(engine inspect -f '{{.State.Running}}' "$KAGEOS_CONTAINER_NAME" 2>/dev/null || true)" == "true" ]]
}

existing_base_url() {
  engine inspect -f '{{range .Config.Env}}{{println .}}{{end}}' "$KAGEOS_CONTAINER_NAME" 2>/dev/null \
    | awk -F= '$1=="CANONICAL_BASE_URL"{print substr($0, index($0, "=")+1); exit}'
}

existing_host_port() {
  local port_line
  port_line="$(engine port "$KAGEOS_CONTAINER_NAME" 80/tcp 2>/dev/null | head -n1 || true)"
  [[ -n "$port_line" ]] || return 1
  printf '%s\n' "$port_line" | awk -F: '{print $NF}'
}

port_in_use() {
  local port="$1"
  if command -v ss >/dev/null 2>&1; then
    ss -H -ltn 2>/dev/null | awk '{print $4}' | grep -Eq "[:.]${port}$" && return 0
  fi
  if command -v lsof >/dev/null 2>&1; then
    lsof -nP -iTCP:"$port" -sTCP:LISTEN >/dev/null 2>&1 && return 0
  fi
  return 1
}

select_port() {
  if [[ "$KAGEOS_PORT" != "auto" ]]; then
    SELECTED_PORT="$KAGEOS_PORT"
    return
  fi

  if container_exists; then
    local previous_port
    previous_port="$(existing_host_port || true)"
    if [[ -n "$previous_port" ]]; then
      SELECTED_PORT="$previous_port"
      return
    fi
  fi

  if [[ "$ENGINE" == "podman" && "$(id -u)" -ne 0 && "${ENGINE_CMD[0]}" != "sudo" ]]; then
    port_in_use 8080 || { SELECTED_PORT="8080"; return; }
  elif ! port_in_use 80; then
    SELECTED_PORT="80"
    return
  fi

  local port
  for port in $(seq 8080 8099); do
    if ! port_in_use "$port"; then
      SELECTED_PORT="$port"
      return
    fi
  done

  die "no free port found in 8080-8099. Pass --port PORT."
}

select_base_url() {
  if [[ -n "$KAGEOS_BASE_URL" ]]; then
    BASE_URL="$KAGEOS_BASE_URL"
    return
  fi

  if container_exists; then
    local previous_base_url
    previous_base_url="$(existing_base_url || true)"
    if [[ -n "$previous_base_url" ]]; then
      BASE_URL="$previous_base_url"
      return
    fi
  fi

  if [[ "$SELECTED_PORT" == "80" ]]; then
    BASE_URL="http://localhost"
  else
    BASE_URL="http://localhost:${SELECTED_PORT}"
  fi
}

install_helper_cli() {
  local tmp
  tmp="$(mktemp)"
  cat >"$tmp" <<'EOF'
#!/usr/bin/env bash
set -Eeuo pipefail

NAME="${KAGEOS_CONTAINER_NAME:-kageos}"
VOLUME="${KAGEOS_VOLUME:-kageos-data}"
ENGINE=""

die() {
  printf 'ERROR: %s\n' "$*" >&2
  exit 1
}

try_engine() {
  local candidate="$1"
  command -v "$candidate" >/dev/null 2>&1 || return 1
  if "$candidate" container inspect "$NAME" >/dev/null 2>&1; then
    ENGINE="$candidate"
    ENGINE_CMD=("$candidate")
    return 0
  fi
  if [[ "$(id -u)" -ne 0 ]] && command -v sudo >/dev/null 2>&1; then
    if (sudo -n true 2>/dev/null || sudo -v) && sudo "$candidate" container inspect "$NAME" >/dev/null 2>&1; then
      ENGINE="$candidate"
      ENGINE_CMD=(sudo "$candidate")
      return 0
    fi
  fi
  return 1
}

detect_engine() {
  ENGINE=""
  ENGINE_CMD=()
  if [[ "${KAGEOS_ENGINE:-auto}" == "podman" || "${KAGEOS_ENGINE:-auto}" == "auto" ]]; then
    try_engine podman && return
  fi
  if [[ "${KAGEOS_ENGINE:-auto}" == "docker" || "${KAGEOS_ENGINE:-auto}" == "auto" ]]; then
    try_engine docker && return
  fi
  die "kageos container not found: ${NAME}"
}

engine() {
  "${ENGINE_CMD[@]}" "$@"
}

usage() {
  cat <<HELP
kageos helper

Usage:
  kageos status
  kageos logs
  kageos password
  kageos url
  kageos start
  kageos stop
  kageos restart
  kageos update
  kageos uninstall [--purge]
HELP
}

command_name="${1:-status}"
shift || true

case "$command_name" in
  help|--help|-h)
    usage
    exit 0
    ;;
esac

detect_engine

case "$command_name" in
  status)
    engine ps -a --filter "name=${NAME}"
    ;;
  logs)
    engine logs -f "$NAME"
    ;;
  password)
    engine exec "$NAME" sh -lc 'cat /var/lib/kageos/secrets/SYSTEM_USER_PASSWORD'
    printf '\n'
    ;;
  url)
    engine exec "$NAME" sh -lc 'printf "%s\n" "${CANONICAL_BASE_URL:-}"'
    ;;
  start)
    engine start "$NAME"
    ;;
  stop)
    engine stop "$NAME"
    ;;
  restart)
    engine restart "$NAME"
    ;;
  update)
    tmp="$(mktemp)"
    curl -fsSL https://kageos.com/install.sh -o "$tmp"
    KAGEOS_ENGINE="$ENGINE" KAGEOS_CONTAINER_NAME="$NAME" KAGEOS_VOLUME="$VOLUME" bash "$tmp" --force
    rm -f "$tmp"
    ;;
  uninstall)
    purge="0"
    if [[ "${1:-}" == "--purge" ]]; then
      purge="1"
    fi
    engine rm -f "$NAME"
    if [[ "$purge" == "1" ]]; then
      engine volume rm "$VOLUME"
    else
      printf 'Data volume kept: %s\n' "$VOLUME"
      printf 'Run "kageos uninstall --purge" to remove data too.\n'
    fi
    ;;
  *)
    usage
    exit 1
    ;;
esac
EOF

  chmod +x "$tmp"
  if root_cmd install -m 0755 "$tmp" /usr/local/bin/kageos; then
    log "Installed helper command: kageos"
  else
    warn "Could not install /usr/local/bin/kageos. You can still manage the container with ${ENGINE}."
  fi
  rm -f "$tmp"
}

print_existing_summary() {
  local password=""
  password="$(engine exec "$KAGEOS_CONTAINER_NAME" sh -lc 'cat /var/lib/kageos/secrets/SYSTEM_USER_PASSWORD 2>/dev/null || true' || true)"
  cat <<EOF

kageos is already installed.

URL:      ${BASE_URL}
Username: system
Password: ${password:-"(not ready yet; run kageos password later)"}

Useful commands:
  kageos status
  kageos logs
  kageos password
  kageos restart
  kageos update

To recreate the container while keeping data:
  curl -fsSL https://kageos.com/install.sh | bash -s -- --force
EOF
}

remove_existing_container_if_needed() {
  if ! container_exists; then
    return
  fi

  if [[ "$KAGEOS_FORCE" == "1" ]]; then
    log "Removing existing container: ${KAGEOS_CONTAINER_NAME}"
    engine rm -f "$KAGEOS_CONTAINER_NAME" >/dev/null
    return
  fi

  if ! container_running; then
    log "Starting existing container: ${KAGEOS_CONTAINER_NAME}"
    engine start "$KAGEOS_CONTAINER_NAME" >/dev/null
  fi
  install_helper_cli
  print_existing_summary
  exit 0
}

start_container() {
  log "Creating persistent volume: ${KAGEOS_VOLUME}"
  engine volume create "$KAGEOS_VOLUME" >/dev/null

  log "Pulling image: ${KAGEOS_IMAGE}"
  engine pull "$KAGEOS_IMAGE"

  log "Starting kageos container: ${KAGEOS_CONTAINER_NAME}"
  engine run -d \
    --name "$KAGEOS_CONTAINER_NAME" \
    --privileged \
    --restart unless-stopped \
    -p "${SELECTED_PORT}:80" \
    -v "${KAGEOS_VOLUME}:/var/lib/kageos" \
    -e "CANONICAL_BASE_URL=${BASE_URL}" \
    -e "KAGEOS_AIO_PRINT_SECRETS=${KAGEOS_AIO_PRINT_SECRETS}" \
    "$KAGEOS_IMAGE" >/dev/null
}

wait_for_start() {
  local deadline
  deadline=$((SECONDS + KAGEOS_START_TIMEOUT))

  log "Waiting for kageos to finish first boot. This can take several minutes."
  while (( SECONDS < deadline )); do
    if engine logs "$KAGEOS_CONTAINER_NAME" 2>&1 | grep -qi "kageos started successfully"; then
      return 0
    fi
    if ! container_running; then
      engine logs "$KAGEOS_CONTAINER_NAME" 2>&1 | tail -n 120 >&2 || true
      die "kageos container stopped before startup completed"
    fi
    sleep 5
  done

  engine logs "$KAGEOS_CONTAINER_NAME" 2>&1 | tail -n 120 >&2 || true
  die "startup did not finish within ${KAGEOS_START_TIMEOUT}s. Run 'kageos logs' to continue watching."
}

print_success_summary() {
  local password=""
  password="$(engine exec "$KAGEOS_CONTAINER_NAME" sh -lc 'cat /var/lib/kageos/secrets/SYSTEM_USER_PASSWORD 2>/dev/null || true' || true)"

  cat <<EOF

kageos installed successfully

URL:      ${BASE_URL}
Username: system
Password: ${password:-"(not ready yet; run kageos password later)"}

Useful commands:
  kageos status
  kageos logs
  kageos password
  kageos stop
  kageos restart
  kageos update

Data is stored in the ${ENGINE} volume:
  ${KAGEOS_VOLUME}
EOF
}

cat <<EOF
kageos local trial installer

Image:     ${KAGEOS_IMAGE}
Container: ${KAGEOS_CONTAINER_NAME}
Volume:    ${KAGEOS_VOLUME}
EOF

select_engine
select_port
select_base_url

cat <<EOF
Engine:    ${ENGINE}
Port:      ${SELECTED_PORT}:80
URL:       ${BASE_URL}
EOF

if [[ "$KAGEOS_DRY_RUN" == "1" ]]; then
  log "Dry run complete. No container was created."
  exit 0
fi

remove_existing_container_if_needed
start_container
install_helper_cli
wait_for_start
print_success_summary
