#!/bin/bash
################################################################################
# Script Name: hestia-geoip-setup.sh
# Version: 1.0
# Description: Configure GeoIP2 enriched logging on HestiaCP / VestaCP /
#              myVesta servers. Installs GeoIP2 module, downloads databases
#              (MaxMind or DB-IP free), creates nginx geoip2 variable mappings
#              and enriched log format in conf.d, builds custom nginx templates
#              with enriched access_log, and optionally applies to domains.
#
# Author: Phil Connor
# Contact: contact@mylinux.work
# Website: https://mylinux.work
# License: MIT
#
# Prerequisites:
#   - HestiaCP or VestaCP/myVesta installed and running
#   - nginx as proxy (default HestiaCP setup)
#   - Root access
#   - MaxMind account OR use --db-ip for no-signup alternative
#
# Usage:
#   sudo ./hestia-geoip-setup.sh --db-ip
#   sudo ./hestia-geoip-setup.sh --db-ip --base-template default-botblock
#   sudo ./hestia-geoip-setup.sh --account-id 123456 --license-key ABCDEF
#   sudo ./hestia-geoip-setup.sh --db-ip --apply admin example.com
#   sudo ./hestia-geoip-setup.sh --db-ip --apply-all admin
#   sudo ./hestia-geoip-setup.sh --dry-run --db-ip
#   sudo ./hestia-geoip-setup.sh --remove
#
################################################################################

set -euo pipefail

# --- Configuration ---
GEOIP_CONF="/etc/GeoIP.conf"
GEOIP_DB_DIR="/usr/share/GeoIP"
NGINX_GEOIP_CONF="/etc/nginx/conf.d/geoip2.conf"
NGINX_LOG_CONF="/etc/nginx/conf.d/enriched-log-format.conf"
APACHE_LOG_CONF="/etc/apache2/conf-available/enriched-log-format.conf"
CRON_WEEKLY="/etc/cron.weekly/geoip-db-update"
CRON_MONTHLY="/etc/cron.monthly/geoip-db-update"
MARKER_START="# geoip-managed-start"
MARKER_END="# geoip-managed-end"
TIMESTAMP=$(date +%s)

TEMPLATE_NAME="default-geoip"
BASE_TEMPLATE="default"
PANEL_TPL_DIR=""
PANEL_NAME=""
APPLY_USER=""
APPLY_DOMAIN=""
APPLY_ALL=false
DRY_RUN=false
REMOVE=false
SKIP_PACKAGES=false
USE_DBIP=false
ACCOUNT_ID="${MAXMIND_ACCOUNT_ID:-}"
LICENSE_KEY="${MAXMIND_LICENSE_KEY:-}"

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

info()  { echo -e "${GREEN}[OK]${NC} $*"; }
warn()  { echo -e "${YELLOW}[WARN]${NC} $*"; }
step()  { echo -e "${CYAN}[STEP]${NC} $*"; }

detect_panel() {
    if [[ -d "/usr/local/hestia/data/templates/web/nginx" ]]; then
        PANEL_TPL_DIR="/usr/local/hestia/data/templates/web/nginx"
        PANEL_NAME="HestiaCP"
    elif [[ -d "/usr/local/vesta/data/templates/web/nginx" ]]; then
        PANEL_TPL_DIR="/usr/local/vesta/data/templates/web/nginx"
        PANEL_NAME="VestaCP/myVesta"
    else
        echo -e "${RED}Error: Neither HestiaCP nor VestaCP/myVesta found${NC}" >&2
        exit 1
    fi
    info "Detected ${PANEL_NAME} (${PANEL_TPL_DIR})"
}

usage() {
    cat <<EOF
Usage: sudo $(basename "$0") [OPTIONS]

Sets up GeoIP2 enriched logging on HestiaCP / VestaCP / myVesta servers.
Creates geoip2 config in conf.d, builds custom nginx templates with enriched
access_log format, and optionally applies them to domains.

Options:
  --db-ip                Use DB-IP free databases (no signup required)
  --account-id ID        MaxMind account ID (not needed with --db-ip)
  --license-key KEY      MaxMind license key (not needed with --db-ip)
  --base-template NAME   Template to build on (default: default)
  --template-name NAME   Name for new template (default: default-geoip)
  --apply USER DOMAIN    Apply template to a specific domain after creation
  --apply-all USER       Apply template to all domains for a user
  --skip-packages        Skip package installation
  --dry-run              Show what would be done without making changes
  --remove               Remove managed configs, templates, and cron
  -h, --help             Show this help

Environment variables:
  MAXMIND_ACCOUNT_ID     MaxMind account ID (overridden by --account-id)
  MAXMIND_LICENSE_KEY    MaxMind license key (overridden by --license-key)

Database providers:
  MaxMind GeoLite2       Free, requires account signup at maxmind.com
  DB-IP Lite             Free, no signup, direct download (--db-ip)

Examples:
  sudo $(basename "$0") --db-ip
  sudo $(basename "$0") --db-ip --base-template default-botblock
  sudo $(basename "$0") --db-ip --base-template default-botblock --apply admin example.com
  sudo $(basename "$0") --db-ip --apply-all admin
  sudo $(basename "$0") --account-id 123456 --license-key ABCDEF
  sudo $(basename "$0") --dry-run --db-ip
  sudo $(basename "$0") --remove
EOF
    exit 0
}

# --- Argument parsing ---
while [[ $# -gt 0 ]]; do
    case "$1" in
        --db-ip)           USE_DBIP=true; shift ;;
        --account-id)      ACCOUNT_ID="$2"; shift 2 ;;
        --license-key)     LICENSE_KEY="$2"; shift 2 ;;
        --base-template)   BASE_TEMPLATE="$2"; shift 2 ;;
        --template-name)   TEMPLATE_NAME="$2"; shift 2 ;;
        --apply)           APPLY_USER="$2"; APPLY_DOMAIN="$3"; shift 3 ;;
        --apply-all)       APPLY_USER="$2"; APPLY_ALL=true; shift 2 ;;
        --skip-packages)   SKIP_PACKAGES=true; shift ;;
        --dry-run)         DRY_RUN=true; shift ;;
        --remove)          REMOVE=true; shift ;;
        -h|--help)         usage ;;
        *)                 echo "Unknown option: $1"; usage ;;
    esac
done

# --- Checks ---
if [[ $EUID -ne 0 ]]; then
    echo -e "${RED}Error: Run as root (sudo)${NC}" >&2
    exit 1
fi

detect_panel

if ! command -v nginx &>/dev/null; then
    echo -e "${RED}Error: nginx not found${NC}" >&2
    exit 1
fi

backup_file() {
    local file="$1"
    if [[ -f "$file" ]]; then
        cp "$file" "${file}.bak.${TIMESTAMP}"
    fi
}

# =====================================================
# REMOVE MODE
# =====================================================
if [[ "$REMOVE" == "true" ]]; then
    step "Removing GeoIP2 configuration"

    for file in "$NGINX_GEOIP_CONF" "$NGINX_LOG_CONF" "$APACHE_LOG_CONF" "$CRON_WEEKLY" "$CRON_MONTHLY"; do
        if [[ -f "$file" ]]; then
            if [[ "$DRY_RUN" == "true" ]]; then
                echo "  Would remove: ${file}"
            else
                rm -f "$file"
                info "Removed: ${file}"
            fi
        else
            warn "Not found: ${file} (already removed?)"
        fi
    done

    # Remove module load config (leave .so in case of reinstall)
    LOAD_MOD_CONF="/etc/nginx/modules-enabled/50-mod-http-geoip2.conf"
    if [[ -f "$LOAD_MOD_CONF" ]]; then
        if [[ "$DRY_RUN" == "true" ]]; then
            echo "  Would remove: ${LOAD_MOD_CONF}"
        else
            rm -f "$LOAD_MOD_CONF"
            info "Removed: ${LOAD_MOD_CONF}"
        fi
    fi

    # Remove nginx templates
    for ext in tpl stpl; do
        tpl_file="${PANEL_TPL_DIR}/${TEMPLATE_NAME}.${ext}"
        if [[ -f "$tpl_file" ]]; then
            if [[ "$DRY_RUN" == "true" ]]; then
                echo "  Would remove: ${tpl_file}"
            else
                rm -f "$tpl_file"
                info "Removed: ${tpl_file}"
            fi
        fi
        # Also check php-fpm directory
        tpl_file="${PANEL_TPL_DIR}/php-fpm/${TEMPLATE_NAME}.${ext}"
        if [[ -f "$tpl_file" ]]; then
            if [[ "$DRY_RUN" == "true" ]]; then
                echo "  Would remove: ${tpl_file}"
            else
                rm -f "$tpl_file"
                info "Removed: ${tpl_file}"
            fi
        fi
    done

    # Remove Apache templates
    for apache_dir in "/usr/local/hestia/data/templates/web/apache2/php-fpm" "/usr/local/hestia/data/templates/web/apache2"; do
        for ext in tpl stpl; do
            tpl_file="${apache_dir}/${TEMPLATE_NAME}.${ext}"
            if [[ -f "$tpl_file" ]]; then
                if [[ "$DRY_RUN" == "true" ]]; then
                    echo "  Would remove: ${tpl_file}"
                else
                    rm -f "$tpl_file"
                    info "Removed: ${tpl_file}"
                fi
            fi
        done
    done

    # Disable Apache enriched log config
    if [[ -f "$APACHE_LOG_CONF" ]]; then
        if [[ "$DRY_RUN" == "true" ]]; then
            echo "  Would run: a2disconf enriched-log-format"
        else
            a2disconf -q enriched-log-format 2>/dev/null || true
        fi
    fi

    if [[ "$DRY_RUN" == "true" ]]; then
        echo "  Would run: nginx -t"
        echo "  Would run: systemctl reload nginx"
    else
        step "Testing nginx configuration"
        if nginx -t 2>&1; then
            info "nginx config valid"
        else
            echo -e "${RED}[ERROR] nginx config test failed — restore .bak files${NC}" >&2
            exit 1
        fi

        step "Reloading nginx"
        systemctl reload nginx
        info "nginx reloaded"

        if systemctl is-active --quiet apache2 2>/dev/null; then
            step "Reloading Apache"
            systemctl reload apache2
            info "Apache reloaded"
        fi
    fi

    echo ""
    echo -e "${BOLD}GeoIP2 configuration removed.${NC}"
    echo "  Domains still using the ${TEMPLATE_NAME} template should be switched back."
    exit 0
fi

# --- Prompt for credentials if not using DB-IP ---
if [[ "$USE_DBIP" != "true" ]]; then
    if [[ -z "$ACCOUNT_ID" ]]; then
        read -rp "MaxMind Account ID (or Ctrl+C and rerun with --db-ip): " ACCOUNT_ID
    fi
    if [[ -z "$LICENSE_KEY" ]]; then
        read -rp "MaxMind License Key: " LICENSE_KEY
    fi

    if [[ -z "$ACCOUNT_ID" || -z "$LICENSE_KEY" ]]; then
        echo -e "${RED}Error: MaxMind credentials required (or use --db-ip for no-signup alternative)${NC}" >&2
        exit 1
    fi
fi

# =====================================================
# Step 1: Install packages and GeoIP2 nginx module
# =====================================================
NGINX_MOD_DIR="/usr/lib/nginx/modules"
GEOIP2_MOD="${NGINX_MOD_DIR}/ngx_http_geoip2_module.so"
LOAD_MOD_CONF="/etc/nginx/modules-enabled/50-mod-http-geoip2.conf"

if [[ "$SKIP_PACKAGES" == "true" ]]; then
    warn "Skipping package installation (--skip-packages)"
else
    # Hestia uses nginx from nginx.org — Ubuntu/Debian libnginx-mod-* packages
    # conflict with it. Install only libmaxminddb-dev + build tools, then compile
    # the geoip2 module as a dynamic .so against the installed nginx.
    step "Installing build dependencies"

    if [[ "$USE_DBIP" == "true" ]]; then
        PACKAGES="libmaxminddb0 libmaxminddb-dev mmdb-bin curl build-essential git libpcre2-dev libssl-dev zlib1g-dev"
    else
        PACKAGES="libmaxminddb0 libmaxminddb-dev mmdb-bin geoipupdate build-essential git libpcre2-dev libssl-dev zlib1g-dev"
    fi

    if [[ "$DRY_RUN" == "true" ]]; then
        echo "  Would run: apt-get update && apt-get install -y ${PACKAGES}"
    else
        apt-get update -qq
        # shellcheck disable=SC2086
        apt-get install -y $PACKAGES
        info "Packages installed: ${PACKAGES}"
    fi

    # Build the geoip2 dynamic module if not already present
    if [[ -f "$GEOIP2_MOD" ]]; then
        info "GeoIP2 module already exists: ${GEOIP2_MOD}"
    else
        step "Building ngx_http_geoip2_module for nginx $(nginx -v 2>&1 | grep -oP '[\d.]+')"

        if [[ "$DRY_RUN" == "true" ]]; then
            echo "  Would compile ngx_http_geoip2_module.so"
        else
            NGINX_VER=$(nginx -v 2>&1 | grep -oP '[\d.]+')
            BUILD_DIR=$(mktemp -d)

            cd "$BUILD_DIR"
            curl -fsSL "https://nginx.org/download/nginx-${NGINX_VER}.tar.gz" -o nginx.tar.gz
            tar xzf nginx.tar.gz

            git clone --depth 1 https://github.com/leev/ngx_http_geoip2_module.git

            cd "nginx-${NGINX_VER}"
            ./configure --with-compat --add-dynamic-module=../ngx_http_geoip2_module
            make modules

            mkdir -p "$NGINX_MOD_DIR"
            cp objs/ngx_http_geoip2_module.so "$NGINX_MOD_DIR/"
            cp objs/ngx_stream_geoip2_module.so "$NGINX_MOD_DIR/" 2>/dev/null || true

            cd /
            rm -rf "$BUILD_DIR"
            info "Built and installed: ${GEOIP2_MOD}"
        fi
    fi

    # Ensure the module is loaded
    if [[ ! -f "$LOAD_MOD_CONF" ]] && [[ "$DRY_RUN" != "true" ]]; then
        mkdir -p "$(dirname "$LOAD_MOD_CONF")"
        echo "load_module ${GEOIP2_MOD};" > "$LOAD_MOD_CONF"
        info "Created: ${LOAD_MOD_CONF}"
    fi
fi

# =====================================================
# Step 2: Write GeoIP.conf (MaxMind only)
# =====================================================
if [[ "$USE_DBIP" != "true" ]]; then
    step "Writing MaxMind configuration to ${GEOIP_CONF}"

    GEOIP_CONF_CONTENT="${MARKER_START}
AccountID ${ACCOUNT_ID}
LicenseKey ${LICENSE_KEY}
EditionIDs GeoLite2-City GeoLite2-ASN GeoLite2-Country
DatabaseDirectory ${GEOIP_DB_DIR}
${MARKER_END}"

    if [[ "$DRY_RUN" == "true" ]]; then
        echo "  Would create: ${GEOIP_CONF}"
    else
        backup_file "$GEOIP_CONF"
        echo "$GEOIP_CONF_CONTENT" > "$GEOIP_CONF"
        chmod 600 "$GEOIP_CONF"
        info "Created: ${GEOIP_CONF}"
    fi
fi

# =====================================================
# Step 3: Download GeoIP databases
# =====================================================
if [[ "$USE_DBIP" == "true" ]]; then
    step "Downloading DB-IP free databases to ${GEOIP_DB_DIR}"

    DBIP_MONTH=$(date +%Y-%m)

    if [[ "$DRY_RUN" == "true" ]]; then
        echo "  Would download: dbip-country-lite-${DBIP_MONTH}.mmdb.gz"
        echo "  Would download: dbip-asn-lite-${DBIP_MONTH}.mmdb.gz"
    else
        mkdir -p "$GEOIP_DB_DIR"
        cd "$GEOIP_DB_DIR"

        curl -fsSL "https://download.db-ip.com/free/dbip-country-lite-${DBIP_MONTH}.mmdb.gz" -o dbip-country.mmdb.gz
        gunzip -f dbip-country.mmdb.gz
        mv dbip-country.mmdb GeoLite2-City.mmdb
        info "Downloaded: DB-IP Country → GeoLite2-City.mmdb"

        curl -fsSL "https://download.db-ip.com/free/dbip-asn-lite-${DBIP_MONTH}.mmdb.gz" -o dbip-asn.mmdb.gz
        gunzip -f dbip-asn.mmdb.gz
        mv dbip-asn.mmdb GeoLite2-ASN.mmdb
        info "Downloaded: DB-IP ASN → GeoLite2-ASN.mmdb"

        cd - >/dev/null
    fi
else
    step "Downloading MaxMind GeoIP2 databases to ${GEOIP_DB_DIR}"

    if [[ "$DRY_RUN" == "true" ]]; then
        echo "  Would run: mkdir -p ${GEOIP_DB_DIR}"
        echo "  Would run: geoipupdate"
    else
        mkdir -p "$GEOIP_DB_DIR"
        geoipupdate -v
        info "GeoIP2 databases downloaded"
    fi
fi

# =====================================================
# Step 4: Create nginx geoip2 config in conf.d
# =====================================================
step "Creating nginx GeoIP2 config at ${NGINX_GEOIP_CONF}"

NGINX_GEOIP_CONTENT="${MARKER_START}
# GeoIP2 variable mappings — generated by hestia-geoip-setup.sh

geoip2 ${GEOIP_DB_DIR}/GeoLite2-City.mmdb {
    auto_reload 60m;
    \$geoip2_country_code   country iso_code;
    \$geoip2_country_name   country names en;
    \$geoip2_city_name      city names en;
}

geoip2 ${GEOIP_DB_DIR}/GeoLite2-ASN.mmdb {
    auto_reload 60m;
    \$geoip2_asn            autonomous_system_number;
    \$geoip2_asn_org        autonomous_system_organization;
}
${MARKER_END}"

if [[ "$DRY_RUN" == "true" ]]; then
    echo "  Would create: ${NGINX_GEOIP_CONF}"
else
    backup_file "$NGINX_GEOIP_CONF"
    echo "$NGINX_GEOIP_CONTENT" > "$NGINX_GEOIP_CONF"
    info "Created: ${NGINX_GEOIP_CONF}"
fi

# =====================================================
# Step 5: Create enriched log format in conf.d
# =====================================================
step "Creating enriched log format at ${NGINX_LOG_CONF}"

NGINX_LOG_CONTENT="${MARKER_START}
# Enriched log format with GeoIP2 data — generated by hestia-geoip-setup.sh

log_format enriched '\$remote_addr - \$remote_user [\$time_local] '
                    '\"\$request\" \$status \$body_bytes_sent '
                    '\"\$http_referer\" \"\$http_user_agent\" '
                    '\$geoip2_country_code \"\$geoip2_asn_org\"';
${MARKER_END}"

if [[ "$DRY_RUN" == "true" ]]; then
    echo "  Would create: ${NGINX_LOG_CONF}"
else
    backup_file "$NGINX_LOG_CONF"
    echo "$NGINX_LOG_CONTENT" > "$NGINX_LOG_CONF"
    info "Created: ${NGINX_LOG_CONF}"
fi

# =====================================================
# Step 5b: Create Apache enriched log format
# =====================================================
if [[ -d "/etc/apache2/conf-available" ]]; then
    step "Creating Apache enriched log format at ${APACHE_LOG_CONF}"

    APACHE_LOG_CONTENT="${MARKER_START}
# Enriched log format with GeoIP2 data (passed from nginx) — generated by hestia-geoip-setup.sh
LogFormat \"%h %l %u %t \\\"%r\\\" %>s %b \\\"%{Referer}i\\\" \\\"%{User-Agent}i\\\" %{X-GeoIP-Country}i \\\"%{X-GeoIP-ASN}i\\\"\" enriched
${MARKER_END}"

    if [[ "$DRY_RUN" == "true" ]]; then
        echo "  Would create: ${APACHE_LOG_CONF}"
        echo "  Would enable: a2enconf enriched-log-format"
    else
        backup_file "$APACHE_LOG_CONF"
        echo "$APACHE_LOG_CONTENT" > "$APACHE_LOG_CONF"
        a2enconf -q enriched-log-format 2>/dev/null || true
        info "Created and enabled: ${APACHE_LOG_CONF}"
    fi
else
    warn "Apache conf-available directory not found — skipping Apache log format"
fi

# =====================================================
# Step 6: Create custom Hestia templates
# =====================================================

# --- Hestia Apache template patching ---
APACHE_TPL_DIR=""
if [[ -d "/usr/local/hestia/data/templates/web/apache2/php-fpm" ]]; then
    APACHE_TPL_DIR="/usr/local/hestia/data/templates/web/apache2/php-fpm"
elif [[ -d "/usr/local/hestia/data/templates/web/apache2" ]]; then
    APACHE_TPL_DIR="/usr/local/hestia/data/templates/web/apache2"
fi

create_apache_template() {
    local src="$1" dst="$2" label="$3"

    if [[ ! -f "$src" ]]; then
        warn "Source Apache template not found: ${src} — skipping ${label}"
        return
    fi

    if [[ "$DRY_RUN" == "true" ]]; then
        echo "  Would create: ${dst} (from ${src})"
        return
    fi

    backup_file "$dst"

    # Define enriched LogFormat inside the vhost and replace 'combined' with 'enriched'
    APACHE_ENRICHED_FORMAT='    LogFormat "%h %l %u %t \\"%r\\" %>s %b \\"%{Referer}i\\" \\"%{User-Agent}i\\" %{X-GeoIP-Country}i \\"%{X-GeoIP-ASN}i\\"" enriched'

    sed 's/\(CustomLog.*\.log\) combined/\1 enriched/g' "$src" | \
    awk -v fmt="$APACHE_ENRICHED_FORMAT" '
        !injected && /CustomLog/ {
            print fmt
            injected = 1
        }
        { print }
    ' > "$dst"

    if grep -q "enriched" "$dst"; then
        info "Created ${label} template: ${dst}"
    else
        cp "$src" "$dst"
        warn "No 'combined' format found in ${src} — copied unchanged"
    fi
}

if [[ -n "$APACHE_TPL_DIR" ]]; then
    # Apache templates may use a different base than nginx (e.g., bot-blocking
    # only exists in the nginx layer). Fall back to 'default' if base not found.
    APACHE_BASE="$BASE_TEMPLATE"
    if [[ ! -f "${APACHE_TPL_DIR}/${APACHE_BASE}.tpl" ]]; then
        APACHE_BASE="default"
        warn "Apache base template '${BASE_TEMPLATE}' not found — falling back to 'default'"
    fi

    step "Creating custom Apache templates (${TEMPLATE_NAME}) from ${APACHE_BASE}"

    create_apache_template \
        "${APACHE_TPL_DIR}/${APACHE_BASE}.tpl" \
        "${APACHE_TPL_DIR}/${TEMPLATE_NAME}.tpl" \
        "Apache HTTP (.tpl)"

    create_apache_template \
        "${APACHE_TPL_DIR}/${APACHE_BASE}.stpl" \
        "${APACHE_TPL_DIR}/${TEMPLATE_NAME}.stpl" \
        "Apache SSL (.stpl)"
fi

# --- Nginx template patching ---
create_template() {
    local src="$1" dst="$2" label="$3"

    if [[ ! -f "$src" ]]; then
        warn "Source template not found: ${src} — skipping ${label}"
        return
    fi

    if [[ "$DRY_RUN" == "true" ]]; then
        echo "  Would create: ${dst} (from ${src})"
        return
    fi

    backup_file "$dst"

    # Replace 'combined' with 'enriched' in access_log directives
    # and inject proxy_set_header lines after the first proxy_pass directive.
    # If the base template has no proxy_set_header directives, nginx defaults
    # (Host, Connection) are lost when ANY proxy_set_header is added — the
    # classic inheritance trap. Include the standard set to prevent 421 errors.
    local has_proxy_headers
    has_proxy_headers=$(grep -c 'proxy_set_header' "$src" || true)

    sed 's/\(access_log.*\.log\) combined;/\1 enriched;/g' "$src" | \
    awk -v d='$' -v need_std="$has_proxy_headers" '
        !injected && /proxy_pass/ {
            print
            if (need_std == 0) {
                print "\t\tproxy_set_header Host " d "host;"
                print "\t\tproxy_set_header X-Real-IP " d "remote_addr;"
                print "\t\tproxy_set_header X-Forwarded-For " d "proxy_add_x_forwarded_for;"
                print "\t\tproxy_set_header X-Forwarded-Proto " d "scheme;"
            }
            print "\t\tproxy_set_header X-GeoIP-Country " d "geoip2_country_code;"
            print "\t\tproxy_set_header X-GeoIP-ASN " d "geoip2_asn_org;"
            injected = 1
            next
        }
        { print }
    ' > "$dst"

    # Verify changes
    if grep -q "enriched" "$dst"; then
        info "Created ${label} template: ${dst} (log format updated)"
    else
        warn "No 'combined' log format found in ${src} — format not changed"
        warn "  Manually change access_log format to 'enriched' in ${dst}"
    fi

    if grep -q "proxy_set_header X-GeoIP-Country" "$dst"; then
        info "Injected GeoIP proxy headers into ${dst}"
    else
        warn "No proxy_pass found in ${src} — GeoIP headers not injected"
    fi
}

step "Creating custom ${PANEL_NAME} templates (${TEMPLATE_NAME}) from ${BASE_TEMPLATE}"

# Proxy templates (nginx as proxy for apache)
create_template \
    "${PANEL_TPL_DIR}/${BASE_TEMPLATE}.tpl" \
    "${PANEL_TPL_DIR}/${TEMPLATE_NAME}.tpl" \
    "proxy HTTP (.tpl)"

create_template \
    "${PANEL_TPL_DIR}/${BASE_TEMPLATE}.stpl" \
    "${PANEL_TPL_DIR}/${TEMPLATE_NAME}.stpl" \
    "proxy SSL (.stpl)"

# php-fpm templates (nginx standalone)
if [[ -d "${PANEL_TPL_DIR}/php-fpm" ]]; then
    if [[ -f "${PANEL_TPL_DIR}/php-fpm/${BASE_TEMPLATE}.tpl" ]]; then
        create_template \
            "${PANEL_TPL_DIR}/php-fpm/${BASE_TEMPLATE}.tpl" \
            "${PANEL_TPL_DIR}/php-fpm/${TEMPLATE_NAME}.tpl" \
            "php-fpm HTTP (.tpl)"

        create_template \
            "${PANEL_TPL_DIR}/php-fpm/${BASE_TEMPLATE}.stpl" \
            "${PANEL_TPL_DIR}/php-fpm/${TEMPLATE_NAME}.stpl" \
            "php-fpm SSL (.stpl)"
    fi
fi

# Copy .sh hook if base template has one
for tpl_dir in "${PANEL_TPL_DIR}" "${PANEL_TPL_DIR}/php-fpm"; do
    if [[ -f "${tpl_dir}/${BASE_TEMPLATE}.sh" ]] && [[ ! -f "${tpl_dir}/${TEMPLATE_NAME}.sh" ]]; then
        if [[ "$DRY_RUN" == "true" ]]; then
            echo "  Would copy: ${tpl_dir}/${BASE_TEMPLATE}.sh → ${tpl_dir}/${TEMPLATE_NAME}.sh"
        else
            cp "${tpl_dir}/${BASE_TEMPLATE}.sh" "${tpl_dir}/${TEMPLATE_NAME}.sh"
            info "Copied hook: ${tpl_dir}/${TEMPLATE_NAME}.sh"
        fi
    fi
done

# =====================================================
# Step 7: Create cron job for database updates
# =====================================================
if [[ "$USE_DBIP" == "true" ]]; then
    CRON_FILE="$CRON_MONTHLY"
    step "Creating monthly DB-IP update script at ${CRON_FILE}"

    CRON_CONTENT="#!/bin/sh
# Monthly DB-IP database update — generated by hestia-geoip-setup.sh
MONTH=\$(date +%Y-%m)
cd ${GEOIP_DB_DIR} && \\
  curl -fsSL \"https://download.db-ip.com/free/dbip-country-lite-\${MONTH}.mmdb.gz\" | gunzip > GeoLite2-City.mmdb && \\
  curl -fsSL \"https://download.db-ip.com/free/dbip-asn-lite-\${MONTH}.mmdb.gz\" | gunzip > GeoLite2-ASN.mmdb && \\
  logger -t dbip-update \"DB-IP databases updated\""
else
    CRON_FILE="$CRON_WEEKLY"
    step "Creating weekly geoipupdate script at ${CRON_FILE}"

    CRON_CONTENT="#!/bin/sh
# Weekly GeoIP2 database update — generated by hestia-geoip-setup.sh
/usr/bin/geoipupdate -s 2>&1 | logger -t geoipupdate"
fi

if [[ "$DRY_RUN" == "true" ]]; then
    echo "  Would create: ${CRON_FILE}"
else
    backup_file "$CRON_FILE"
    echo "$CRON_CONTENT" > "$CRON_FILE"
    chmod 755 "$CRON_FILE"
    info "Created: ${CRON_FILE}"
fi

# =====================================================
# Step 8: Validate nginx config
# =====================================================
step "Testing nginx configuration"

if [[ "$DRY_RUN" == "true" ]]; then
    echo "  Would run: nginx -t"
else
    if nginx -t 2>&1; then
        info "nginx config valid"
    else
        echo -e "${RED}[ERROR] nginx config test failed${NC}" >&2
        echo "  Restore backups (.bak.${TIMESTAMP}) and check templates" >&2
        exit 1
    fi
fi

# =====================================================
# Step 9: Apply template (optional)
# =====================================================
if [[ -n "$APPLY_USER" ]]; then
    if ! command -v v-change-web-domain-proxy-tpl &>/dev/null; then
        echo -e "${RED}Error: v-change-web-domain-proxy-tpl not found${NC}" >&2
        exit 1
    fi

    # Apply nginx proxy template
    if [[ "$APPLY_ALL" == "true" ]]; then
        step "Applying nginx proxy template to all domains for user: ${APPLY_USER}"
        domains=$(v-list-web-domains "$APPLY_USER" plain 2>/dev/null | awk '{print $1}')
        if [[ -z "$domains" ]]; then
            warn "No domains found for user: ${APPLY_USER}"
        else
            while IFS= read -r domain; do
                if [[ "$DRY_RUN" == "true" ]]; then
                    echo "  Would apply: v-change-web-domain-proxy-tpl ${APPLY_USER} ${domain} ${TEMPLATE_NAME}"
                else
                    v-change-web-domain-proxy-tpl "$APPLY_USER" "$domain" "$TEMPLATE_NAME"
                    info "Nginx proxy template applied to: ${domain}"
                fi
            done <<< "$domains"
        fi
    else
        step "Applying nginx proxy template to: ${APPLY_DOMAIN}"
        if [[ "$DRY_RUN" == "true" ]]; then
            echo "  Would apply: v-change-web-domain-proxy-tpl ${APPLY_USER} ${APPLY_DOMAIN} ${TEMPLATE_NAME}"
        else
            v-change-web-domain-proxy-tpl "$APPLY_USER" "$APPLY_DOMAIN" "$TEMPLATE_NAME"
            info "Nginx proxy template applied to: ${APPLY_DOMAIN}"
        fi
    fi

    # Apply Apache backend template (if Apache templates were created)
    if [[ -n "$APACHE_TPL_DIR" ]] && [[ -f "${APACHE_TPL_DIR}/${TEMPLATE_NAME}.tpl" ]]; then
        if command -v v-change-web-domain-tpl &>/dev/null; then
            if [[ "$APPLY_ALL" == "true" ]]; then
                step "Applying Apache backend template to all domains for user: ${APPLY_USER}"
                while IFS= read -r domain; do
                    if [[ "$DRY_RUN" == "true" ]]; then
                        echo "  Would apply: v-change-web-domain-tpl ${APPLY_USER} ${domain} ${TEMPLATE_NAME}"
                    else
                        v-change-web-domain-tpl "$APPLY_USER" "$domain" "$TEMPLATE_NAME"
                        info "Apache template applied to: ${domain}"
                    fi
                done <<< "$domains"
            else
                step "Applying Apache backend template to: ${APPLY_DOMAIN}"
                if [[ "$DRY_RUN" == "true" ]]; then
                    echo "  Would apply: v-change-web-domain-tpl ${APPLY_USER} ${APPLY_DOMAIN} ${TEMPLATE_NAME}"
                else
                    v-change-web-domain-tpl "$APPLY_USER" "$APPLY_DOMAIN" "$TEMPLATE_NAME"
                    info "Apache template applied to: ${APPLY_DOMAIN}"
                fi
            fi
        fi
    fi
fi

# =====================================================
# Step 10: Reload nginx and Apache
# =====================================================
step "Reloading web servers"

if [[ "$DRY_RUN" == "true" ]]; then
    echo "  Would run: systemctl reload nginx"
    echo "  Would run: systemctl reload apache2"
else
    systemctl reload nginx
    info "nginx reloaded"

    if systemctl is-active --quiet apache2 2>/dev/null; then
        systemctl reload apache2
        info "Apache reloaded"
    fi
fi

# =====================================================
# Summary
# =====================================================
echo ""
echo -e "${BOLD}Done.${NC}"
echo ""
echo "  GeoIP config: ${NGINX_GEOIP_CONF}"
echo "  Log format:   ${NGINX_LOG_CONF}"
echo "  Template:     ${TEMPLATE_NAME} (.tpl + .stpl)"
echo "  Base:         ${BASE_TEMPLATE}"
echo "  DB updates:   ${CRON_FILE}"
if [[ "$USE_DBIP" == "true" ]]; then
    echo "  DB source:    DB-IP Lite (no signup)"
else
    echo "  DB source:    MaxMind GeoLite2"
fi
if [[ -n "$APPLY_USER" ]]; then
    if [[ "$APPLY_ALL" == "true" ]]; then
        echo "  Applied:      All domains for ${APPLY_USER}"
    else
        echo "  Applied:      ${APPLY_DOMAIN}"
    fi
else
    echo ""
    echo "  To apply to a domain:"
    echo "    v-change-web-domain-proxy-tpl <user> <domain> ${TEMPLATE_NAME}"
    echo ""
    echo "  To apply to all domains for a user:"
    echo "    sudo $(basename "$0") --apply-all <user>"
fi
echo ""
echo "  To remove:    sudo $(basename "$0") --remove"
