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

umask 022

PROJECT_NAME="getbible-mcp"
SOURCE_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
INSTALL_ROOT="/opt/${PROJECT_NAME}"
CURRENT_LINK="${INSTALL_ROOT}/current"
ENV_FILE="/etc/${PROJECT_NAME}.env"
SERVICE_FILE="/etc/systemd/system/${PROJECT_NAME}.service"
NGINX_SITE="/etc/nginx/sites-available/mcp.getbible.net.conf"
NGINX_ENABLED="/etc/nginx/sites-enabled/mcp.getbible.net.conf"

usage() {
    cat <<'EOF'
Usage: sudo ./manage ACTION

Actions:
  install      Build and atomically activate a new release, then start services
  update       Same safe release process as install
  status       Show systemd, local health, and Nginx configuration status
  logs         Follow service logs
  uninstall   Remove service and Nginx integration; preserve releases and config
  purge --yes Remove service, Nginx integration, releases, and environment file
EOF
}

require_root() {
    if [[ ${EUID} -ne 0 ]]; then
        echo "Run this action as root, for example: sudo ./manage $*" >&2
        exit 1
    fi
}

require_command() {
    if ! command -v "$1" >/dev/null 2>&1; then
        echo "Required command not found: $1" >&2
        exit 1
    fi
}

ensure_service_user() {
    if ! id getbible-mcp >/dev/null 2>&1; then
        useradd --system --home /nonexistent --shell /usr/sbin/nologin getbible-mcp
    fi
}

install_nginx_files() {
    local installed_new_site=0

    if [[ ! -f ${NGINX_SITE} ]]; then
        install -o root -g root -m 0644 \
            "${SOURCE_DIR}/deploy/nginx/sites-available/mcp.getbible.net.conf" "${NGINX_SITE}"
        installed_new_site=1
    else
        echo "Preserving existing ${NGINX_SITE} (including any Certbot-managed TLS changes)."
    fi
    ln -sfn "${NGINX_SITE}" "${NGINX_ENABLED}"

    if ! nginx -t; then
        echo "Nginx validation failed; restoring the previous configuration." >&2
        if [[ ${installed_new_site} -eq 1 ]]; then
            rm -f "${NGINX_SITE}" "${NGINX_ENABLED}"
        fi
        exit 1
    fi
}

deploy_release() {
    require_root install
    require_command python3
    require_command rsync
    require_command systemctl
    require_command nginx
    require_command curl
    ensure_service_user

    local release_id
    local release_dir
    local previous=""
    local next_link="${INSTALL_ROOT}/.current-next"

    release_id="$(date -u +%Y%m%dT%H%M%SZ)-$$"
    release_dir="${INSTALL_ROOT}/releases/${release_id}"
    install -d -o root -g root -m 0755 "${release_dir}"

    rsync -a --delete \
        --exclude '.git/' \
        --exclude '.venv/' \
        --exclude 'build/' \
        --exclude 'dist/' \
        --exclude '__pycache__/' \
        "${SOURCE_DIR}/" "${release_dir}/"

    python3 -m venv "${release_dir}/.venv"
    "${release_dir}/.venv/bin/python" -m pip install --disable-pip-version-check \
        --no-cache-dir -r "${release_dir}/requirements.txt"
    "${release_dir}/.venv/bin/python" -m pip install --disable-pip-version-check \
        --no-cache-dir --no-deps "${release_dir}"

    chown -R root:root "${release_dir}"
    chmod 0755 "${INSTALL_ROOT}" "${INSTALL_ROOT}/releases" "${release_dir}"

    if [[ -L ${CURRENT_LINK} ]]; then
        previous="$(readlink -f "${CURRENT_LINK}")"
    fi
    rm -f "${next_link}"
    ln -s "${release_dir}" "${next_link}"
    mv -Tf "${next_link}" "${CURRENT_LINK}"

    if [[ ! -f ${ENV_FILE} ]]; then
        install -o root -g getbible-mcp -m 0640 \
            "${release_dir}/deploy/getbible-mcp.env" "${ENV_FILE}"
    fi
    install -o root -g root -m 0644 \
        "${release_dir}/deploy/getbible-mcp.service" "${SERVICE_FILE}"
    install_nginx_files

    systemctl daemon-reload
    systemctl enable "${PROJECT_NAME}.service" >/dev/null
    if ! systemctl restart "${PROJECT_NAME}.service"; then
        echo "The new release failed to start." >&2
        if [[ -n ${previous} ]]; then
            rm -f "${next_link}"
            ln -s "${previous}" "${next_link}"
            mv -Tf "${next_link}" "${CURRENT_LINK}"
            systemctl restart "${PROJECT_NAME}.service" || true
            echo "The previous release was restored: ${previous}" >&2
        fi
        exit 1
    fi

    local healthy=0
    for _ in {1..20}; do
        if curl --silent --show-error --fail http://127.0.0.1:3100/healthz >/dev/null; then
            healthy=1
            break
        fi
        sleep 1
    done
    if [[ ${healthy} -ne 1 ]]; then
        echo "Service started but did not pass its local health check." >&2
        if [[ -n ${previous} ]]; then
            rm -f "${next_link}"
            ln -s "${previous}" "${next_link}"
            mv -Tf "${next_link}" "${CURRENT_LINK}"
            systemctl restart "${PROJECT_NAME}.service" || true
            echo "The previous release was restored: ${previous}" >&2
        fi
        exit 1
    fi

    systemctl reload nginx
    echo "Activated ${release_dir}"
    echo "Local health check passed. Configure TLS with Certbot if this is the first deployment."
}

show_status() {
    require_root status
    systemctl --no-pager --full status "${PROJECT_NAME}.service" || true
    echo
    echo "Local health:"
    curl --silent --show-error --fail http://127.0.0.1:3100/healthz || true
    echo
    nginx -t
}

uninstall_service() {
    require_root uninstall
    systemctl disable --now "${PROJECT_NAME}.service" 2>/dev/null || true
    rm -f "${SERVICE_FILE}" "${NGINX_ENABLED}" "${NGINX_SITE}"
    systemctl daemon-reload
    nginx -t
    systemctl reload nginx
    echo "Service and Nginx integration removed. Releases and ${ENV_FILE} were preserved."
}

purge_all() {
    require_root purge
    if [[ ${1:-} != "--yes" ]]; then
        echo "Purging removes all releases and configuration. Re-run: sudo ./manage purge --yes" >&2
        exit 1
    fi
    uninstall_service
    rm -rf "${INSTALL_ROOT}"
    rm -f "${ENV_FILE}"
    if id getbible-mcp >/dev/null 2>&1; then
        userdel getbible-mcp 2>/dev/null || true
    fi
    echo "GetBible MCP was purged."
}

action="${1:-help}"
case "${action}" in
    install|update) deploy_release ;;
    status) show_status ;;
    logs)
        require_root logs
        journalctl -u "${PROJECT_NAME}.service" -f
        ;;
    uninstall) uninstall_service ;;
    purge) purge_all "${2:-}" ;;
    help|-h|--help) usage ;;
    *)
        echo "Unknown action: ${action}" >&2
        usage >&2
        exit 2
        ;;
esac
