#!/bin/bash
# =============================================================================
# Modular Hosting Setup with optional Cloudflare Tunnel
# Author Fedya Serafiev
# Site itpraktika.com
# =============================================================================

set -euo pipefail

# -- Colors -------------------------------------------------------------------
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
CYAN='\033[0;36m'; BOLD='\033[1m'; RESET='\033[0m'

info()    { echo -e "${CYAN}[INFO]  $*${RESET}"; }
success() { echo -e "${GREEN}[OK]    $*${RESET}"; }
warn()    { echo -e "${YELLOW}[WARN]  $*${RESET}"; }
error()   { echo -e "${RED}[ERROR] $*${RESET}" >&2; exit 1; }

gen_pass() {
    openssl rand -base64 32 | tr -dc 'a-zA-Z0-9' | head -c 24
}
validate_yn() {
    [[ "$1" =~ ^[yYnN]$ ]] || error "Vuvedete 'y' ili 'n'."
}
validate_count() {
    [[ "$1" =~ ^[0-2]$ ]] || error "Vuvedete 0, 1 ili 2."
}

# -- Create DB user directly in running MariaDB -------------------------------
create_db_user() {
    local db_name="$1"
    local db_user="$2"
    local db_pass="$3"
    local root_pass="$4"
    local db_container="$5"

    info "Creating database '$db_name' and user '$db_user' ..."
    docker exec "$db_container" mariadb -u root -p"${root_pass}" -e "
        CREATE DATABASE IF NOT EXISTS ${db_name} CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
        CREATE USER IF NOT EXISTS '${db_user}'@'%' IDENTIFIED BY '${db_pass}';
        GRANT ALL PRIVILEGES ON ${db_name}.* TO '${db_user}'@'%';
        FLUSH PRIVILEGES;
    " && success "Database '$db_name' ready." || error "Failed to create database '$db_name'."
}

# -- Find running container by partial name -----------------------------------
find_container() {
    docker ps --format '{{.Names}}' 2>/dev/null | grep "$1" | head -1
}

# =============================================================================
# Detect already running containers
# =============================================================================
CF_CONTAINER=$(find_container "cloudflared")
KUMA_CONTAINER=$(find_container "uptime-kuma")
WP1_CONTAINER=$(find_container "wp1")
WP2_CONTAINER=$(find_container "wp2")
DB_CONTAINER=$(find_container "db")

HAVE_CF=false;   [[ -n "$CF_CONTAINER" ]]   && HAVE_CF=true
HAVE_KUMA=false; [[ -n "$KUMA_CONTAINER" ]] && HAVE_KUMA=true
HAVE_WP1=false;  [[ -n "$WP1_CONTAINER" ]]  && HAVE_WP1=true
HAVE_WP2=false;  [[ -n "$WP2_CONTAINER" ]]  && HAVE_WP2=true
HAVE_DB=false;   [[ -n "$DB_CONTAINER" ]]   && HAVE_DB=true

SERVER_IP=$(hostname -I | awk '{print $1}')

# =============================================================================
echo -e "\n${BOLD}================================================${RESET}"
echo -e "${BOLD}     Modular Hosting Setup - Izberete moduli    ${RESET}"
echo -e "${BOLD}================================================${RESET}\n"

echo -e "${BOLD}Tekushto sastoyanie:${RESET}"
$HAVE_CF   && echo -e "  ${GREEN}[running]${RESET}       Cloudflare Tunnel" || echo -e "  ${YELLOW}[not installed]${RESET} Cloudflare Tunnel"
$HAVE_KUMA && echo -e "  ${GREEN}[running]${RESET}       Uptime Kuma"       || echo -e "  ${YELLOW}[not installed]${RESET} Uptime Kuma"
$HAVE_WP1  && echo -e "  ${GREEN}[running]${RESET}       WordPress 1"       || echo -e "  ${YELLOW}[not installed]${RESET} WordPress 1"
$HAVE_WP2  && echo -e "  ${GREEN}[running]${RESET}       WordPress 2"       || echo -e "  ${YELLOW}[not installed]${RESET} WordPress 2"
echo ""

# =============================================================================
# [1/4] What to ADD
# =============================================================================
echo -e "${BOLD}[1/4] Koe iskate da DOBAVITE:${RESET}\n"

ADD_CF="n"; ADD_KUMA="n"; ADD_WP1=false; ADD_WP2=false

if $HAVE_CF; then
    info "Cloudflare Tunnel - veche e instaliran, preskachame."
else
    read -rp "  Instaliraj Cloudflare Tunnel? (y/n): " ADD_CF
    validate_yn "$ADD_CF"; ADD_CF="${ADD_CF,,}"
fi

if $HAVE_KUMA; then
    info "Uptime Kuma - veche e instaliran, preskachame."
else
    read -rp "  Instaliraj Uptime Kuma?        (y/n): " ADD_KUMA
    validate_yn "$ADD_KUMA"; ADD_KUMA="${ADD_KUMA,,}"
fi

if $HAVE_WP1 && $HAVE_WP2; then
    info "I dvata WordPress sajta veche sa instalиrani, preskachame."
elif $HAVE_WP1 && ! $HAVE_WP2; then
    info "WordPress 1 veche e instaliran."
    read -rp "  Dobavi WordPress 2? (y/n): " _add2
    validate_yn "$_add2"
    [[ "${_add2,,}" == "y" ]] && ADD_WP2=true
elif ! $HAVE_WP1 && ! $HAVE_WP2; then
    read -rp "  Broy WordPress sajtove? (0/1/2): " _wpc
    validate_count "$_wpc"
    [[ "$_wpc" -ge 1 ]] && ADD_WP1=true
    [[ "$_wpc" -ge 2 ]] && ADD_WP2=true
fi

# Nothing new?
if [[ "$ADD_CF" == "n" && "$ADD_KUMA" == "n" ]] && ! $ADD_WP1 && ! $ADD_WP2; then
    warn "Nyama nishto novo za dobavyane. Izlizame."
    exit 0
fi

# =============================================================================
# [2/4] Cloudflare config
# =============================================================================
CLOUDFLARED_CMD=""
CF_ENV_LINE=""
CF_TOKEN_IN_ENV="# Cloudflare Tunnel not installed"
cf_method=""

if [[ "$ADD_CF" == "y" ]]; then
    echo -e "\n${BOLD}[2/4] Cloudflare Tunnel - metod${RESET}"
    echo "  1) Token  - gotov token ot Cloudflare Dashboard"
    echo "  2) Login  - cloudflared se logva sam (URL)"
    echo ""
    read -rp "  Izberi metod [1/2]: " cf_method
    case "$cf_method" in
      1)
        read -rp "  Tunnel Token: " cf_token
        [[ -n "$cf_token" ]] || error "Tokenat ne mozhe da e prazen."
        CLOUDFLARED_CMD='tunnel --no-autoupdate run --token ${TUNNEL_TOKEN}'
        CF_ENV_LINE="      - TUNNEL_TOKEN=\${TUNNEL_TOKEN}"
        CF_TOKEN_IN_ENV="TUNNEL_TOKEN=$cf_token"
        ;;
      2)
        CLOUDFLARED_CMD='tunnel --no-autoupdate login'
        CF_TOKEN_IN_ENV="# TUNNEL_TOKEN= (login method)"
        cf_token=""
        ;;
      *) error "Nevaliden izbor." ;;
    esac
fi

# =============================================================================
# [3/4] Passwords — keep existing, generate only what is missing
# =============================================================================
echo -e "\n${BOLD}[3/4] Paroli...${RESET}"

[[ -f .env ]] && set -a && source .env 2>/dev/null && set +a || true

DB_ROOT_PASS="${DB_ROOT_PASSWORD:-$(gen_pass)}"
WP1_DB_PASS="${WP1_DB_PASSWORD:-$(gen_pass)}"
WP2_DB_PASS="${WP2_DB_PASSWORD:-$(gen_pass)}"

# =============================================================================
# [4/4] Generate docker-compose.yml
# =============================================================================
echo -e "\n${BOLD}[4/4] Generiranje na fajlove...${RESET}"

# -- .env ---------------------------------------------------------------------
cat > .env <<ENVEOF
# -- Cloudflare ---------------------------------------------------------------
$CF_TOKEN_IN_ENV

# -- Database -----------------------------------------------------------------
DB_ROOT_PASSWORD=$DB_ROOT_PASS
WP1_DB_PASSWORD=$WP1_DB_PASS
WP2_DB_PASSWORD=$WP2_DB_PASS
ENVEOF
chmod 600 .env
success ".env updated"

# -- db-init (only for fresh installs, no DB running yet) ---------------------
if ! $HAVE_DB; then
    mkdir -p db-init
    SQL=""
    $ADD_WP1 && SQL+="CREATE DATABASE IF NOT EXISTS wp1_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;\nCREATE USER IF NOT EXISTS 'wp1_user'@'%' IDENTIFIED BY '${WP1_DB_PASS}';\nGRANT ALL PRIVILEGES ON wp1_db.* TO 'wp1_user'@'%';\n"
    $ADD_WP2 && SQL+="CREATE DATABASE IF NOT EXISTS wp2_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;\nCREATE USER IF NOT EXISTS 'wp2_user'@'%' IDENTIFIED BY '${WP2_DB_PASS}';\nGRANT ALL PRIVILEGES ON wp2_db.* TO 'wp2_user'@'%';\n"
    SQL+="FLUSH PRIVILEGES;\n"
    printf "%b" "$SQL" > db-init/01-init.sql
    success "db-init/01-init.sql created"
fi

# -- docker-compose.yml -------------------------------------------------------
cat > docker-compose.yml <<DCEOF
services:
DCEOF

# Cloudflare
if $HAVE_CF || [[ "$ADD_CF" == "y" ]]; then
    USE_CMD="$CLOUDFLARED_CMD"
    $HAVE_CF && USE_CMD='tunnel --no-autoupdate run --token ${TUNNEL_TOKEN}'
cat >> docker-compose.yml <<DCEOF

  # -- Cloudflare Tunnel -------------------------------------------------------
  cloudflared:
    image: cloudflare/cloudflared:latest
    restart: always
    command: $USE_CMD
    environment:
      - TUNNEL_TOKEN=\${TUNNEL_TOKEN}
    networks:
      - internal
DCEOF
fi

# MariaDB
NEED_DB=false
( $HAVE_DB || $HAVE_WP1 || $HAVE_WP2 || $ADD_WP1 || $ADD_WP2 ) && NEED_DB=true

if $NEED_DB; then
cat >> docker-compose.yml <<DCEOF

  # -- Database ----------------------------------------------------------------
  db:
    image: mariadb:10.6
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: \${DB_ROOT_PASSWORD}
    volumes:
      - db_data:/var/lib/mysql
      - ./db-init:/docker-entrypoint-initdb.d:ro
    networks:
      - internal
    healthcheck:
      test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
      interval: 10s
      timeout: 5s
      retries: 5
DCEOF
fi

# Uptime Kuma
if $HAVE_KUMA || [[ "$ADD_KUMA" == "y" ]]; then
cat >> docker-compose.yml <<DCEOF

  # -- Uptime Kuma -------------------------------------------------------------
  uptime-kuma:
    image: louislam/uptime-kuma:latest
    container_name: uptime-kuma
    restart: always
    ports:
      - "3001:3001"
    volumes:
      - kuma_data:/app/data
    networks:
      - internal
DCEOF
fi

# WordPress 1
if $HAVE_WP1 || $ADD_WP1; then
cat >> docker-compose.yml <<DCEOF

  # -- WordPress 1 -------------------------------------------------------------
  wp1:
    image: wordpress:latest
    restart: always
    depends_on:
      db:
        condition: service_healthy
    ports:
      - "8081:80"
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: wp1_user
      WORDPRESS_DB_PASSWORD: \${WP1_DB_PASSWORD}
      WORDPRESS_DB_NAME: wp1_db
    volumes:
      - wp1_data:/var/www/html
    networks:
      - internal
DCEOF
fi

# WordPress 2
if $HAVE_WP2 || $ADD_WP2; then
cat >> docker-compose.yml <<DCEOF

  # -- WordPress 2 -------------------------------------------------------------
  wp2:
    image: wordpress:latest
    restart: always
    depends_on:
      db:
        condition: service_healthy
    ports:
      - "8082:80"
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: wp2_user
      WORDPRESS_DB_PASSWORD: \${WP2_DB_PASSWORD}
      WORDPRESS_DB_NAME: wp2_db
    volumes:
      - wp2_data:/var/www/html
    networks:
      - internal
DCEOF
fi

# Networks & Volumes
cat >> docker-compose.yml <<DCEOF

networks:
  internal:
    driver: bridge

volumes:
DCEOF

$NEED_DB                                    && echo "  db_data:"   >> docker-compose.yml
( $HAVE_KUMA || [[ "$ADD_KUMA" == "y" ]] )  && echo "  kuma_data:" >> docker-compose.yml
( $HAVE_WP1  || $ADD_WP1 )                  && echo "  wp1_data:"  >> docker-compose.yml
( $HAVE_WP2  || $ADD_WP2 )                  && echo "  wp2_data:"  >> docker-compose.yml

success "docker-compose.yml updated"

# =============================================================================
# Create DB users for newly added WordPress (DB is already running)
# =============================================================================
if $HAVE_DB; then
    if $ADD_WP1; then
        create_db_user "wp1_db" "wp1_user" "$WP1_DB_PASS" "$DB_ROOT_PASS" "$DB_CONTAINER"
    fi
    if $ADD_WP2; then
        create_db_user "wp2_db" "wp2_user" "$WP2_DB_PASS" "$DB_ROOT_PASS" "$DB_CONTAINER"
    fi
fi

# -- Apply changes ------------------------------------------------------------
echo ""
info "Prilagame promените s 'docker compose up -d' ..."
docker compose up -d
success "Vsichko e startиrano!"

# =============================================================================
# Summary with real URLs
# =============================================================================
echo ""
echo -e "${BOLD}================================================${RESET}"
echo -e "${BOLD}         Dostap do uslugite / Access URLs       ${RESET}"
echo -e "${BOLD}================================================${RESET}"

( $HAVE_WP1 || $ADD_WP1 ) && echo -e "  WordPress 1  : ${GREEN}http://${SERVER_IP}:8081${RESET}"
( $HAVE_WP2 || $ADD_WP2 ) && echo -e "  WordPress 2  : ${GREEN}http://${SERVER_IP}:8082${RESET}"
( $HAVE_KUMA || [[ "$ADD_KUMA" == "y" ]] ) && echo -e "  Uptime Kuma  : ${GREEN}http://${SERVER_IP}:3001${RESET}"
( $HAVE_CF   || [[ "$ADD_CF"   == "y" ]] ) && echo -e "  Cloudflare   : ${CYAN}(configured via Cloudflare Dashboard)${RESET}"

echo ""
warn "Keep .env in a safe place - it contains your passwords!"
echo -e "${BOLD}================================================${RESET}\n"