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

APP_NAME="singbox-gopanel"
SERVICE_NAME="singbox-gopanel"
INSTALL_DIR="/opt/${APP_NAME}"
RUN_USER="${SUDO_USER:-${USER:-root}}"
SKIP_SERVICE="false"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PACKAGE_DIR="${SCRIPT_DIR}"
BIN_NAME="api"

usage() {
  cat <<EOF
Usage: install.sh [options]

Options:
  --install-dir <dir>    Install directory, default: ${INSTALL_DIR}
  --service-name <name>  systemd service name, default: ${SERVICE_NAME}
  --run-user <user>      Runtime user, default: ${RUN_USER}
  --package-dir <dir>    Package directory, default: ${PACKAGE_DIR}
  --skip-service         Skip systemd service installation
  -h, --help             Show this help

Expected package layout:
  ${BIN_NAME}
  frontend/
  docs/
  README.md
  .env.example (optional)

Example:
  sudo bash ./install.sh --install-dir /opt/singbox-gopanel --run-user root
EOF
}

parse_args() {
  while [[ $# -gt 0 ]]; do
    case "$1" in
      --install-dir)
        INSTALL_DIR="$2"
        shift 2
        ;;
      --service-name)
        SERVICE_NAME="$2"
        shift 2
        ;;
      --run-user)
        RUN_USER="$2"
        shift 2
        ;;
      --package-dir)
        PACKAGE_DIR="$2"
        shift 2
        ;;
      --skip-service)
        SKIP_SERVICE="true"
        shift
        ;;
      -h|--help)
        usage
        exit 0
        ;;
      *)
        echo "error: unknown option: $1" >&2
        usage
        exit 1
        ;;
    esac
  done
}

ensure_root() {
  if [[ "${EUID}" -ne 0 ]]; then
    echo "error: please run as root or via sudo" >&2
    exit 1
  fi
}

ensure_run_user() {
  if ! id "${RUN_USER}" >/dev/null 2>&1; then
    echo "error: run user does not exist: ${RUN_USER}" >&2
    exit 1
  fi
}

ensure_package_layout() {
  if [[ ! -f "${PACKAGE_DIR}/${BIN_NAME}" ]]; then
    echo "error: binary not found: ${PACKAGE_DIR}/${BIN_NAME}" >&2
    exit 1
  fi
  if [[ ! -d "${PACKAGE_DIR}/frontend" ]]; then
    echo "error: frontend directory not found: ${PACKAGE_DIR}/frontend" >&2
    exit 1
  fi
  if [[ ! -d "${PACKAGE_DIR}/docs" ]]; then
    echo "error: docs directory not found: ${PACKAGE_DIR}/docs" >&2
    exit 1
  fi
}

prepare_dirs() {
  mkdir -p "${INSTALL_DIR}"
  mkdir -p "${INSTALL_DIR}/frontend"
  mkdir -p "${INSTALL_DIR}/docs"
}

copy_runtime_files() {
  echo "copying package files into ${INSTALL_DIR}..."

  install -m 0755 "${PACKAGE_DIR}/${BIN_NAME}" "${INSTALL_DIR}/${BIN_NAME}"

  rm -rf "${INSTALL_DIR}/frontend"
  mkdir -p "${INSTALL_DIR}/frontend"
  cp -R "${PACKAGE_DIR}/frontend/." "${INSTALL_DIR}/frontend/"

  rm -rf "${INSTALL_DIR}/docs"
  mkdir -p "${INSTALL_DIR}/docs"
  cp -R "${PACKAGE_DIR}/docs/." "${INSTALL_DIR}/docs/"

  if [[ -f "${PACKAGE_DIR}/README.md" ]]; then
    cp -f "${PACKAGE_DIR}/README.md" "${INSTALL_DIR}/README.md"
  fi

  if [[ -f "${PACKAGE_DIR}/.env.example" ]]; then
    cp -f "${PACKAGE_DIR}/.env.example" "${INSTALL_DIR}/.env.example"
  fi

  if [[ -f "${PACKAGE_DIR}/.env" && ! -f "${INSTALL_DIR}/.env" ]]; then
    cp -f "${PACKAGE_DIR}/.env" "${INSTALL_DIR}/.env"
  fi

  if [[ ! -f "${INSTALL_DIR}/.env" && -f "${INSTALL_DIR}/.env.example" ]]; then
    cp -f "${INSTALL_DIR}/.env.example" "${INSTALL_DIR}/.env"
    echo "created ${INSTALL_DIR}/.env from .env.example"
  fi
}

install_service() {
  if [[ "${SKIP_SERVICE}" == "true" ]]; then
    echo "skip service enabled"
    return
  fi

  if ! command -v systemctl >/dev/null 2>&1; then
    echo "systemctl not found, skipping service installation"
    return
  fi

  cat >"/etc/systemd/system/${SERVICE_NAME}.service" <<EOF
[Unit]
Description=SingBox GoPanel API
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=${RUN_USER}
WorkingDirectory=${INSTALL_DIR}
EnvironmentFile=-${INSTALL_DIR}/.env
ExecStart=${INSTALL_DIR}/${BIN_NAME}
Restart=always
RestartSec=5
LimitNOFILE=1048576

[Install]
WantedBy=multi-user.target
EOF

  systemctl daemon-reload
  systemctl enable "${SERVICE_NAME}"
  systemctl restart "${SERVICE_NAME}"
}

print_summary() {
  cat <<EOF

Install complete.

Package dir:       ${PACKAGE_DIR}
Install directory: ${INSTALL_DIR}
Binary:            ${INSTALL_DIR}/${BIN_NAME}
Frontend:          ${INSTALL_DIR}/frontend
Docs:              ${INSTALL_DIR}/docs
Service name:      ${SERVICE_NAME}

Next steps:
  1. Edit ${INSTALL_DIR}/.env if needed
  2. Check service status: systemctl status ${SERVICE_NAME}
  3. Tail logs: journalctl -u ${SERVICE_NAME} -f
EOF
}

main() {
  parse_args "$@"
  if [[ ! -f "${PACKAGE_DIR}/${BIN_NAME}" && -f "${SCRIPT_DIR}/../${BIN_NAME}" ]]; then
    PACKAGE_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
  fi
  ensure_root
  ensure_run_user
  ensure_package_layout
  prepare_dirs
  copy_runtime_files
  chown -R "${RUN_USER}:${RUN_USER}" "${INSTALL_DIR}" || true
  chmod +x "${INSTALL_DIR}/${BIN_NAME}" || true
  install_service
  print_summary
}

main "$@"
