#!/usr/bin/env bash

######################################################################################
#### install-webtop.sh — Deploy LinuxServer.io Webtop behind nginx reverse proxy  ####
#### Installs Docker, runs Webtop container with persistent config, configures    ####
#### nginx with basic auth and WebSocket proxy for KasmVNC.                       ####
#### Requires: Ubuntu 22.04+, root access                                         ####
####                                                                              ####
#### Author: Phil Connor                                                          ####
#### Contact: contact@mylinux.work                                                ####
#### License: MIT                                                                 ####
#### Version 1.00                                                                 ####
####                                                                              ####
#### Usage:                                                                       ####
####   sudo ./install-webtop.sh --domain webtop.example.com                       ####
####   sudo ./install-webtop.sh --domain webtop.example.com --no-ssl              ####
####   sudo ./install-webtop.sh --domain webtop.example.com --allow-ip 1.2.3.4    ####
####                                                                              ####
#### See --help for all options.                                                  ####
######################################################################################

set -euo pipefail

# ── Defaults ──────────────────────────────────────────────────────────
DOMAIN=""
DESKTOP="fedora-mate"
WEBTOP_IMAGE=""
CONTAINER_NAME="webtop"
CONFIG_DIR="/opt/webtop"
INTERNAL_PORT="3000"
TIMEZONE="${TZ:-America/Chicago}"
SHM_SIZE="1gb"
ALLOW_IP=""
NO_SSL=false
AUTH_USER="admin"
AUTH_PASS=""
SKIP_DOCKER=false

# ── Colors ────────────────────────────────────────────────────────────
if [[ -t 1 ]]; then
    GREEN='\033[0;32m'
    YELLOW='\033[0;33m'
    RED='\033[0;31m'
    BLUE='\033[0;34m'
    BOLD='\033[1m'
    RESET='\033[0m'
else
    GREEN="" YELLOW="" RED="" BLUE="" BOLD="" RESET=""
fi

log()  { echo -e "${GREEN}[OK]${RESET} $*"; }
warn() { echo -e "${YELLOW}[WARN]${RESET} $*"; }
err()  { echo -e "${RED}[ERROR]${RESET} $*" >&2; }
step() { echo -e "\n${BOLD}── $* ──${RESET}"; }

# ── Help ──────────────────────────────────────────────────────────────
show_help() {
    cat <<'EOF'
Usage: install-webtop.sh [OPTIONS]

Deploy LinuxServer.io Webtop (Fedora MATE) behind nginx reverse proxy
with basic auth, WebSocket support, and optional Let's Encrypt SSL.

Required:
  --domain DOMAIN       Domain name for nginx vhost and SSL cert

Options:
  --desktop DESKTOP     Desktop environment (default: fedora-mate)
                        Options: fedora-mate, fedora-xfce, fedora-kde,
                                 ubuntu-mate, ubuntu-xfce, ubuntu-kde,
                                 alpine-xfce, alpine-kde
  --image IMAGE         Override with a custom image tag
  --name NAME           Container name (default: webtop)
  --config-dir PATH     Persistent config directory (default: /opt/webtop)
  --port PORT           Internal KasmVNC port (default: 3000)
  --tz TIMEZONE         Timezone (default: America/Chicago)
  --shm-size SIZE       Shared memory size (default: 1gb)
  --allow-ip IP         Restrict access to this IP in UFW (optional)
  --auth-user USER      Basic auth username (default: admin)
  --auth-pass PASS      Basic auth password (prompted if not set)
  --no-ssl              Skip Let's Encrypt — use HTTP only
  --skip-docker         Skip Docker installation (already installed)
  -h, --help            Show this help

Examples:
  sudo ./install-webtop.sh --domain webtop.example.com
  sudo ./install-webtop.sh --domain webtop.example.com --allow-ip 203.0.113.50
  sudo ./install-webtop.sh --domain webtop.example.com --desktop ubuntu-xfce
  sudo ./install-webtop.sh --domain webtop.example.com --no-ssl --auth-pass s3cret
EOF
    exit 0
}

# ── Parse Arguments ───────────────────────────────────────────────────
parse_args() {
    while [[ $# -gt 0 ]]; do
        case "$1" in
            --domain)       DOMAIN="$2"; shift 2 ;;
            --desktop)      DESKTOP="$2"; shift 2 ;;
            --image)        WEBTOP_IMAGE="$2"; shift 2 ;;
            --name)         CONTAINER_NAME="$2"; shift 2 ;;
            --config-dir)   CONFIG_DIR="$2"; shift 2 ;;
            --port)         INTERNAL_PORT="$2"; shift 2 ;;
            --tz)           TIMEZONE="$2"; shift 2 ;;
            --shm-size)     SHM_SIZE="$2"; shift 2 ;;
            --allow-ip)     ALLOW_IP="$2"; shift 2 ;;
            --auth-user)    AUTH_USER="$2"; shift 2 ;;
            --auth-pass)    AUTH_PASS="$2"; shift 2 ;;
            --no-ssl)       NO_SSL=true; shift ;;
            --skip-docker)  SKIP_DOCKER=true; shift ;;
            -h|--help)      show_help ;;
            *)              err "Unknown option: $1"; echo "Run with --help for usage."; exit 1 ;;
        esac
    done

    if [[ -z "$DOMAIN" ]]; then
        err "--domain is required"
        exit 1
    fi

    # resolve image from desktop choice (--image overrides)
    if [[ -z "$WEBTOP_IMAGE" ]]; then
        local valid_desktops="fedora-mate fedora-xfce fedora-kde ubuntu-mate ubuntu-xfce ubuntu-kde alpine-xfce alpine-kde"
        if ! echo "$valid_desktops" | grep -qw "$DESKTOP"; then
            err "Unknown desktop: ${DESKTOP}"
            echo "Valid options: ${valid_desktops}"
            exit 1
        fi
        WEBTOP_IMAGE="lscr.io/linuxserver/webtop:${DESKTOP}"
    fi
}

# ── Root Check ────────────────────────────────────────────────────────
check_root() {
    if [[ $EUID -ne 0 ]]; then
        err "This script must be run as root."
        exit 1
    fi
}

# ── Install Docker ────────────────────────────────────────────────────
install_docker() {
    step "Docker"

    if [[ "$SKIP_DOCKER" == "true" ]]; then
        log "Skipping Docker install (--skip-docker)"
        return
    fi

    if command -v docker &>/dev/null; then
        log "Docker already installed: $(docker --version)"
        return
    fi

    curl -fsSL https://get.docker.com | sh
    systemctl enable --now docker
    log "Docker installed: $(docker --version)"
}

# ── Create Config Directory ───────────────────────────────────────────
setup_config_dir() {
    step "Config directory"
    mkdir -p "${CONFIG_DIR}"
    log "Persistent config: ${CONFIG_DIR}"
}

# ── Run Webtop Container ─────────────────────────────────────────────
run_webtop() {
    step "Webtop container"

    if docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
        warn "Container '${CONTAINER_NAME}' already exists — removing"
        docker rm -f "${CONTAINER_NAME}" >/dev/null 2>&1
    fi

    docker run -d \
        --name "${CONTAINER_NAME}" \
        --restart unless-stopped \
        -p "127.0.0.1:${INTERNAL_PORT}:3000" \
        -e PUID=1000 \
        -e PGID=1000 \
        -e "TZ=${TIMEZONE}" \
        -v "${CONFIG_DIR}:/config" \
        --shm-size="${SHM_SIZE}" \
        "${WEBTOP_IMAGE}"

    log "Container '${CONTAINER_NAME}' running (${WEBTOP_IMAGE})"
    log "Bound to 127.0.0.1:${INTERNAL_PORT} (nginx will proxy)"
}

# ── Install nginx ─────────────────────────────────────────────────────
install_nginx() {
    step "nginx"

    if ! command -v nginx &>/dev/null; then
        apt-get update -qq
        apt-get install -y -qq nginx apache2-utils >/dev/null
        log "nginx installed"
    else
        log "nginx already installed"
        if ! command -v htpasswd &>/dev/null; then
            apt-get install -y -qq apache2-utils >/dev/null
        fi
    fi
}

# ── Basic Auth ────────────────────────────────────────────────────────
setup_auth() {
    step "Basic auth"

    if [[ -z "$AUTH_PASS" ]]; then
        AUTH_PASS=$(openssl rand -base64 16)
    fi

    htpasswd -bc /etc/nginx/.htpasswd_webtop "${AUTH_USER}" "${AUTH_PASS}" 2>/dev/null
    chown root:www-data /etc/nginx/.htpasswd_webtop
    chmod 640 /etc/nginx/.htpasswd_webtop

    # save credentials to a root-only file
    local creds_file="${CONFIG_DIR}/.credentials"
    echo "username=${AUTH_USER}" > "${creds_file}"
    echo "password=${AUTH_PASS}" >> "${creds_file}"
    chmod 600 "${creds_file}"

    log "Basic auth configured (user: ${AUTH_USER})"
    log "Credentials saved to ${creds_file} (root-only)"
}

# ── nginx Vhost ───────────────────────────────────────────────────────
configure_nginx() {
    step "nginx vhost"

    cat > "/etc/nginx/sites-available/${DOMAIN}" <<NGINX
server {
    listen 80;
    listen [::]:80;
    server_name ${DOMAIN};

    auth_basic "Webtop";
    auth_basic_user_file /etc/nginx/.htpasswd_webtop;

    location / {
        proxy_pass http://127.0.0.1:${INTERNAL_PORT};
        proxy_http_version 1.1;
        proxy_set_header Upgrade \$http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host \$host;
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto \$scheme;

        proxy_buffering off;
        proxy_read_timeout 86400s;
        proxy_send_timeout 86400s;
    }
}
NGINX

    ln -sf "/etc/nginx/sites-available/${DOMAIN}" /etc/nginx/sites-enabled/

    nginx -t 2>&1
    systemctl reload nginx
    log "nginx vhost configured: ${DOMAIN}"
}

# ── Let's Encrypt SSL ────────────────────────────────────────────────
setup_ssl() {
    step "SSL (Let's Encrypt)"

    if [[ "$NO_SSL" == "true" ]]; then
        warn "Skipping SSL (--no-ssl) — access via http://${DOMAIN}"
        return
    fi

    if ! command -v certbot &>/dev/null; then
        apt-get install -y -qq certbot python3-certbot-nginx >/dev/null
        log "certbot installed"
    fi

    certbot --nginx -d "${DOMAIN}" --non-interactive --agree-tos \
        --register-unsafely-without-email --redirect

    log "SSL configured: https://${DOMAIN}"
}

# ── UFW Rules ─────────────────────────────────────────────────────────
setup_ufw() {
    step "Firewall"

    if ! command -v ufw &>/dev/null; then
        warn "UFW not found — skipping firewall config"
        return
    fi

    ufw allow OpenSSH >/dev/null 2>&1 || true
    ufw allow 'Nginx Full' >/dev/null 2>&1 || true

    if [[ -n "$ALLOW_IP" ]]; then
        ufw deny from any to any port 80 >/dev/null 2>&1 || true
        ufw deny from any to any port 443 >/dev/null 2>&1 || true
        ufw allow from "${ALLOW_IP}" to any port 80 >/dev/null 2>&1 || true
        ufw allow from "${ALLOW_IP}" to any port 443 >/dev/null 2>&1 || true
        log "Access restricted to ${ALLOW_IP}"
    else
        log "nginx ports open (no IP restriction)"
        warn "Consider using --allow-ip to restrict access"
    fi

    if ! ufw status | grep -q "^Status: active"; then
        ufw --force enable >/dev/null 2>&1
        log "UFW enabled"
    fi
}

# ── Summary ───────────────────────────────────────────────────────────
print_summary() {
    local proto="http"
    if [[ "$NO_SSL" == "false" ]]; then
        proto="https"
    fi

    echo ""
    echo "────────────────────────────────────────"
    echo -e "${BOLD}Webtop Deployment Complete${RESET}"
    echo "────────────────────────────────────────"
    echo "  URL:        ${proto}://${DOMAIN}"
    echo "  Username:   ${AUTH_USER}"
    echo "  Password:   ${AUTH_PASS}"
    echo "  Creds file: ${CONFIG_DIR}/.credentials"
    echo "  Image:      ${WEBTOP_IMAGE}"
    echo "  Container:  ${CONTAINER_NAME}"
    echo "  Config:     ${CONFIG_DIR}"
    echo "  Timezone:   ${TIMEZONE}"
    if [[ -n "$ALLOW_IP" ]]; then
        echo "  Allowed IP: ${ALLOW_IP}"
    fi
    echo "────────────────────────────────────────"
    echo ""
    echo "Manage:"
    echo "  docker logs ${CONTAINER_NAME}       # view logs"
    echo "  docker restart ${CONTAINER_NAME}    # restart"
    echo "  docker stop ${CONTAINER_NAME}       # stop"
    echo "  docker start ${CONTAINER_NAME}      # start"
    echo "  ls ${CONFIG_DIR}/                   # persistent data"
}

# ── Main ──────────────────────────────────────────────────────────────
main() {
    parse_args "$@"
    check_root

    echo -e "${BOLD}Webtop Installer${RESET}"
    echo "Domain:  ${DOMAIN}"
    echo "Image:   ${WEBTOP_IMAGE}"
    echo "Config:  ${CONFIG_DIR}"

    install_docker
    setup_config_dir
    run_webtop
    install_nginx
    setup_auth
    configure_nginx
    setup_ssl
    setup_ufw
    print_summary
}

main "$@"
