#!/usr/bin/env bash
# onx-vhost-add — Create a web server vhost from template (dispatcher).
#
# Driver-aware: 'server' parametresine göre Apache/Nginx/Caddy/OLS sub-script'ine
# delege eder. Server parametresi belirtilmezse veya 'apache' ise mevcut Apache
# işleme akışı devam eder. System subdomain modu (webmail_proxy, panel_redirect,
# webdisk, mail_autoconfig) yalnız Apache'de desteklenir.
#
# Input (stdin JSON):
#   server               string   apache | nginx | caddy | openlitespeed | litespeed  (default: apache)
#   username             string   Linux username (onx_xxx)
#   domain               string   Primary ServerName
#   server_aliases       array    Additional ServerAlias entries (optional)
#   doc_root             string   DocumentRoot path
#   php_version          string   "8.1", "8.2", "8.3", etc.
#   ssl_enabled          bool     Include SSL VirtualHost block?
#   cert_path            string   Fullchain PEM (required if ssl_enabled)
#   key_path             string   Private key PEM (required if ssl_enabled)
#   reverse_proxy        bool     Nginx önde + Apache arkada modu (Nginx-only)
#
#   --- System subdomain mode (cPanel-style, Apache-only) ---
#   is_system_subdomain  bool     If true, use a system subdomain template instead of normal vhost.
#   subdomain_type       string   webmail_proxy | panel_redirect | webdisk | mail_autoconfig
#   parent_domain        string   The owning domain (used for cert path and ServerAdmin).
#   proxy_pass           string   (optional) Upstream URL for reverse proxy templates.
#   redirect_to          string   (optional) Target URL for panel_redirect template.
#
# Output (stdout JSON):
#   {"vhost_path":..., "reloaded":true, "ssl_enabled":..., "server":..., "is_system_subdomain":..., "subdomain_type":...}
#
# Exit codes: 0=ok 1=invalid-input 2=preflight-fail 3=exec-fail 4=rolled-back
#
# Deployed to: /usr/local/onoxsoft/bin/onx-vhost-add

set -euo pipefail

SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
# shellcheck source=_lib/common.sh
source "${SCRIPT_DIR}/_lib/common.sh"

# ── Constants ────────────────────────────────────────────────────────────────
TEMPLATE_PATH="/usr/local/onoxsoft/templates/vhost.conf.stub"
VHOST_DIR="/etc/httpd/conf.d/sites"
ACME_WEBROOT="/var/lib/letsencrypt/.well-known/acme-challenge"
ROUNDCUBE_PATH="/usr/share/roundcubemail"
AUTODISCOVER_PATH="/usr/local/onoxsoft/autodiscover"

# ── Read & parse stdin ───────────────────────────────────────────────────────
INPUT=$(cat)

onx_require_json "${INPUT}"

# ── Dispatcher: driver != apache ise sub-script'e delege et ─────────────────
SERVER=$(onx_json_get "${INPUT}" "server" "apache")
IS_SYSTEM_SUBDOMAIN_PRECHECK=$(onx_json_get_bool "${INPUT}" "is_system_subdomain" "false")

# System subdomain modu yalnız Apache'de — diğer driver'lar için fallback Apache.
# (Webmail proxy, panel redirect vs. Apache-specific config gerektirir.)
if [[ "${IS_SYSTEM_SUBDOMAIN_PRECHECK}" != "true" ]]; then
  case "${SERVER}" in
    apache)
      : # bu script Apache işleme akışı ile devam eder
      ;;
    nginx)
      SUB_SCRIPT="${SCRIPT_DIR}/onx-vhost-add-nginx"
      [[ -x "${SUB_SCRIPT}" ]] || onx_die 2 "nginx sub-script not found or not executable: ${SUB_SCRIPT}"
      printf '%s' "${INPUT}" | exec "${SUB_SCRIPT}"
      ;;
    caddy)
      SUB_SCRIPT="${SCRIPT_DIR}/onx-vhost-add-caddy"
      [[ -x "${SUB_SCRIPT}" ]] || onx_die 2 "caddy sub-script not found or not executable: ${SUB_SCRIPT}"
      printf '%s' "${INPUT}" | exec "${SUB_SCRIPT}"
      ;;
    openlitespeed|litespeed)
      SUB_SCRIPT="${SCRIPT_DIR}/onx-vhost-add-ols"
      [[ -x "${SUB_SCRIPT}" ]] || onx_die 2 "ols sub-script not found or not executable: ${SUB_SCRIPT}"
      printf '%s' "${INPUT}" | exec "${SUB_SCRIPT}"
      ;;
    *)
      onx_die 1 "unknown server: ${SERVER} (expected: apache|nginx|caddy|openlitespeed|litespeed)"
      ;;
  esac
fi

USERNAME=$(onx_json_get "${INPUT}" "username")
DOMAIN=$(onx_json_get "${INPUT}" "domain")
DOC_ROOT=$(onx_json_get "${INPUT}" "doc_root")
PHP_VERSION=$(onx_json_get "${INPUT}" "php_version" "8.2")
SSL_ENABLED=$(onx_json_get_bool "${INPUT}" "ssl_enabled" "false")
CERT_PATH=$(onx_json_get "${INPUT}" "cert_path" "")
KEY_PATH=$(onx_json_get "${INPUT}" "key_path" "")

# System subdomain mode
IS_SYSTEM_SUBDOMAIN=$(onx_json_get_bool "${INPUT}" "is_system_subdomain" "false")
SUBDOMAIN_TYPE=$(onx_json_get "${INPUT}" "subdomain_type" "default")
PARENT_DOMAIN=$(onx_json_get "${INPUT}" "parent_domain" "")
PROXY_PASS=$(onx_json_get "${INPUT}" "proxy_pass" "")
REDIRECT_TO=$(onx_json_get "${INPUT}" "redirect_to" "")

# ── Input validation ─────────────────────────────────────────────────────────
onx_validate_username "${USERNAME}"
onx_validate_domain "${DOMAIN}"

[[ -z "${DOC_ROOT}" ]] && onx_die 1 "doc_root is required"

# php_version "8.2" → "82" (used in paths like php82-php-fpm)
PHP_VERSION_NODOT="${PHP_VERSION//./}"

# ── Preflight ────────────────────────────────────────────────────────────────
[[ -d "${VHOST_DIR}" ]]      || onx_die 2 "vhost directory not found: ${VHOST_DIR}"
command -v apachectl >/dev/null 2>&1 || onx_die 2 "apachectl not found"

# Normal (non-system) vhost requires user home dir
if [[ "${IS_SYSTEM_SUBDOMAIN}" != "true" ]]; then
  [[ -f "${TEMPLATE_PATH}" ]]  || onx_die 2 "vhost template not found: ${TEMPLATE_PATH}"
  [[ -d "/home/${USERNAME}" ]] || onx_die 2 "home directory not found: /home/${USERNAME}"
fi

if [[ "${SSL_ENABLED}" == "true" ]]; then
  [[ -n "${CERT_PATH}" ]] || onx_die 1 "cert_path required when ssl_enabled"
  [[ -n "${KEY_PATH}" ]]  || onx_die 1 "key_path required when ssl_enabled"
  [[ -f "${CERT_PATH}" ]] || onx_die 2 "cert_path does not exist: ${CERT_PATH}"
  [[ -f "${KEY_PATH}" ]]  || onx_die 2 "key_path does not exist: ${KEY_PATH}"
fi

# Ensure log directory exists (system subdomains share user logs)
mkdir -p "/home/${USERNAME}/logs"

VHOST_PATH="${VHOST_DIR}/${USERNAME}-${DOMAIN}.conf"
BACKUP_PATH="${VHOST_PATH}.bak.$$"

# Back up existing vhost file (if any) before writing new one
[[ -f "${VHOST_PATH}" ]] && cp "${VHOST_PATH}" "${BACKUP_PATH}"

# ── SSL cert resolution for system subdomains ──────────────────────────────
# If cert_path not explicitly given but parent_domain is, fall back to parent cert.
if [[ "${IS_SYSTEM_SUBDOMAIN}" == "true" && "${SSL_ENABLED}" == "true" ]]; then
  if [[ -z "${CERT_PATH}" && -n "${PARENT_DOMAIN}" ]]; then
    CERT_PATH="/etc/letsencrypt/live/${PARENT_DOMAIN}/fullchain.pem"
    KEY_PATH="/etc/letsencrypt/live/${PARENT_DOMAIN}/privkey.pem"
  fi
fi

# ── System subdomain template branch ────────────────────────────────────────
if [[ "${IS_SYSTEM_SUBDOMAIN}" == "true" ]]; then
  # Build SSL block (shared by all SSL-enabled templates)
  SSL_BLOCK=""
  if [[ "${SSL_ENABLED}" == "true" ]]; then
    SSL_BLOCK=$(cat <<SSLBLOCK
    SSLEngine on
    SSLCertificateFile ${CERT_PATH}
    SSLCertificateKeyFile ${KEY_PATH}
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
SSLBLOCK
)
  fi

  case "${SUBDOMAIN_TYPE}" in
    webmail_proxy)
      # mail.<domain>, webmail.<domain> → Roundcube under /usr/share/roundcubemail
      cat > "${VHOST_PATH}" <<EOF
# Auto-generated by onx-vhost-add (subdomain_type=webmail_proxy)
# Parent: ${PARENT_DOMAIN}
<VirtualHost *:80>
    ServerName ${DOMAIN}
    DocumentRoot ${ROUNDCUBE_PATH}

    RewriteEngine On
    RewriteCond %{HTTPS} off
    RewriteCond %{REQUEST_URI} !^/.well-known/acme-challenge/
    RewriteRule ^(.*)\$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

    ErrorLog /home/${USERNAME}/logs/${DOMAIN}-error.log
    CustomLog /home/${USERNAME}/logs/${DOMAIN}-access.log combined
</VirtualHost>

EOF
      if [[ "${SSL_ENABLED}" == "true" ]]; then
        cat >> "${VHOST_PATH}" <<EOF
<VirtualHost *:443>
    ServerName ${DOMAIN}
    DocumentRoot ${ROUNDCUBE_PATH}

${SSL_BLOCK}

    <Directory "${ROUNDCUBE_PATH}">
        Options FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

    <FilesMatch \\.php\$>
        SetHandler "proxy:unix:/var/opt/remi/php${PHP_VERSION_NODOT}/run/php-fpm/www.sock|fcgi://localhost"
    </FilesMatch>

    ErrorLog /home/${USERNAME}/logs/${DOMAIN}-ssl-error.log
    CustomLog /home/${USERNAME}/logs/${DOMAIN}-ssl-access.log combined
</VirtualHost>
EOF
      fi
      ;;

    panel_redirect)
      # panel.<domain> → ONOXSOFT panel admin URL (302)
      [[ -z "${REDIRECT_TO}" ]] && onx_die 1 "redirect_to required for panel_redirect template"
      cat > "${VHOST_PATH}" <<EOF
# Auto-generated by onx-vhost-add (subdomain_type=panel_redirect)
# Parent: ${PARENT_DOMAIN}
<VirtualHost *:80>
    ServerName ${DOMAIN}
    RewriteEngine On
    RewriteCond %{REQUEST_URI} !^/.well-known/acme-challenge/
    RewriteRule ^(.*)\$ ${REDIRECT_TO}\$1 [L,R=302]
    ErrorLog /home/${USERNAME}/logs/${DOMAIN}-error.log
</VirtualHost>

EOF
      if [[ "${SSL_ENABLED}" == "true" ]]; then
        cat >> "${VHOST_PATH}" <<EOF
<VirtualHost *:443>
    ServerName ${DOMAIN}

${SSL_BLOCK}

    RewriteEngine On
    RewriteRule ^(.*)\$ ${REDIRECT_TO}\$1 [L,R=302]
    ErrorLog /home/${USERNAME}/logs/${DOMAIN}-ssl-error.log
</VirtualHost>
EOF
      fi
      ;;

    webdisk)
      # webdisk.<domain> → WebDAV mount under /home/<user>/public_html
      cat > "${VHOST_PATH}" <<EOF
# Auto-generated by onx-vhost-add (subdomain_type=webdisk)
# Parent: ${PARENT_DOMAIN}
EOF
      if [[ "${SSL_ENABLED}" == "true" ]]; then
        cat >> "${VHOST_PATH}" <<EOF
<VirtualHost *:443>
    ServerName ${DOMAIN}
    DocumentRoot ${DOC_ROOT}

${SSL_BLOCK}

    DAV On
    <Location />
        AuthType Basic
        AuthName "WebDisk: ${USERNAME}"
        AuthBasicProvider file
        AuthUserFile /home/${USERNAME}/.htpasswds/webdisk
        Require valid-user
    </Location>

    ErrorLog /home/${USERNAME}/logs/${DOMAIN}-error.log
    CustomLog /home/${USERNAME}/logs/${DOMAIN}-access.log combined
</VirtualHost>
EOF
      else
        # WebDisk without SSL is plaintext basic auth — emit warning vhost on :80 only.
        cat >> "${VHOST_PATH}" <<EOF
<VirtualHost *:80>
    ServerName ${DOMAIN}
    DocumentRoot ${DOC_ROOT}

    DAV On
    <Location />
        AuthType Basic
        AuthName "WebDisk: ${USERNAME}"
        AuthBasicProvider file
        AuthUserFile /home/${USERNAME}/.htpasswds/webdisk
        Require valid-user
    </Location>

    ErrorLog /home/${USERNAME}/logs/${DOMAIN}-error.log
    CustomLog /home/${USERNAME}/logs/${DOMAIN}-access.log combined
</VirtualHost>
EOF
      fi
      ;;

    mail_autoconfig)
      # autodiscover.<domain> (Outlook) + autoconfig.<domain> (Thunderbird)
      cat > "${VHOST_PATH}" <<EOF
# Auto-generated by onx-vhost-add (subdomain_type=mail_autoconfig)
# Parent: ${PARENT_DOMAIN}
<VirtualHost *:80>
    ServerName ${DOMAIN}
    DocumentRoot ${AUTODISCOVER_PATH}

    RewriteEngine On
    RewriteRule ^/[Aa]utodiscover/[Aa]utodiscover.xml\$ /autodiscover.xml.php [L]
    RewriteRule ^/mail/config-v1.1.xml\$ /thunderbird.xml.php [L]
    RewriteRule ^/.well-known/autoconfig/mail/config-v1.1.xml\$ /thunderbird.xml.php [L]

    <Directory "${AUTODISCOVER_PATH}">
        Options FollowSymLinks
        AllowOverride None
        Require all granted
    </Directory>

    <FilesMatch \\.php\$>
        SetHandler "proxy:unix:/var/opt/remi/php${PHP_VERSION_NODOT}/run/php-fpm/www.sock|fcgi://localhost"
    </FilesMatch>

    ErrorLog /home/${USERNAME}/logs/${DOMAIN}-error.log
    CustomLog /home/${USERNAME}/logs/${DOMAIN}-access.log combined
</VirtualHost>

EOF
      if [[ "${SSL_ENABLED}" == "true" ]]; then
        cat >> "${VHOST_PATH}" <<EOF
<VirtualHost *:443>
    ServerName ${DOMAIN}
    DocumentRoot ${AUTODISCOVER_PATH}

${SSL_BLOCK}

    RewriteEngine On
    RewriteRule ^/[Aa]utodiscover/[Aa]utodiscover.xml\$ /autodiscover.xml.php [L]
    RewriteRule ^/mail/config-v1.1.xml\$ /thunderbird.xml.php [L]
    RewriteRule ^/.well-known/autoconfig/mail/config-v1.1.xml\$ /thunderbird.xml.php [L]

    <Directory "${AUTODISCOVER_PATH}">
        Options FollowSymLinks
        AllowOverride None
        Require all granted
    </Directory>

    <FilesMatch \\.php\$>
        SetHandler "proxy:unix:/var/opt/remi/php${PHP_VERSION_NODOT}/run/php-fpm/www.sock|fcgi://localhost"
    </FilesMatch>

    ErrorLog /home/${USERNAME}/logs/${DOMAIN}-ssl-error.log
    CustomLog /home/${USERNAME}/logs/${DOMAIN}-ssl-access.log combined
</VirtualHost>
EOF
      fi
      ;;

    *)
      onx_die 1 "unknown subdomain_type: ${SUBDOMAIN_TYPE} (expected: webmail_proxy|panel_redirect|webdisk|mail_autoconfig)"
      ;;
  esac

  chmod 0644 "${VHOST_PATH}"

  # ── apachectl configtest → rollback on failure ─────────────────────────
  if ! apachectl configtest 2>/dev/null; then
    onx_log "apachectl configtest failed (system subdomain) — rolling back"
    if [[ -f "${BACKUP_PATH}" ]]; then
      mv "${BACKUP_PATH}" "${VHOST_PATH}"
    else
      rm -f "${VHOST_PATH}"
    fi
    onx_die 4 "apachectl configtest failed; vhost rolled back"
  fi

  rm -f "${BACKUP_PATH}"

  # ── Reload httpd ───────────────────────────────────────────────────────
  if ! systemctl reload httpd; then
    onx_die 3 "systemctl reload httpd failed"
  fi

  onx_json_out \
    "vhost_path"          "${VHOST_PATH}" \
    "reloaded"            "true" \
    "ssl_enabled"         "${SSL_ENABLED}" \
    "is_system_subdomain" "true" \
    "subdomain_type"      "${SUBDOMAIN_TYPE}" \
    "parent_domain"       "${PARENT_DOMAIN}"

  exit 0
fi

# ── Build alias directives ───────────────────────────────────────────────────
# server_aliases is a JSON array e.g. ["www.example.com","mail.example.com"]
ALIASES_DIRECTIVES=""
while IFS= read -r alias; do
  [[ -n "${alias}" ]] && ALIASES_DIRECTIVES+="  ServerAlias ${alias}"$'\n'
done < <(onx_json_array_items "${INPUT}" "server_aliases")

# ── Build HTTPS-redirect block (only when SSL enabled) ───────────────────────
if [[ "${SSL_ENABLED}" == "true" ]]; then
  HTTPS_REDIRECT_BLOCK=$(cat <<'BLOCK'
  # Redirect all HTTP traffic to HTTPS
  RewriteEngine On
  RewriteCond %{HTTPS} off
  RewriteCond %{REQUEST_URI} !^/.well-known/acme-challenge/
  RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
BLOCK
)
else
  HTTPS_REDIRECT_BLOCK=""
fi

# ── Build HTTPS VirtualHost block ────────────────────────────────────────────
if [[ "${SSL_ENABLED}" == "true" ]]; then
  HTTPS_VHOST_BLOCK=$(cat <<SSLBLOCK
<VirtualHost *:443>
  ServerName ${DOMAIN}
${ALIASES_DIRECTIVES}
  DocumentRoot ${DOC_ROOT}

  CustomLog /home/${USERNAME}/logs/${DOMAIN}-ssl-access.log combined
  ErrorLog  /home/${USERNAME}/logs/${DOMAIN}-ssl-error.log

  SSLEngine on
  SSLCertificateFile    ${CERT_PATH}
  SSLCertificateKeyFile ${KEY_PATH}

  Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"

  <FilesMatch \\.php\$>
    SetHandler "proxy:unix:/var/opt/remi/php${PHP_VERSION_NODOT}/run/php-fpm/${USERNAME}.sock|fcgi://localhost"
  </FilesMatch>

  <Directory ${DOC_ROOT}>
    AllowOverride All
    Require all granted
  </Directory>
</VirtualHost>
SSLBLOCK
)
else
  HTTPS_VHOST_BLOCK=""
fi

# ── Render template via sed substitution ────────────────────────────────────

# Export vars for sed inline replacement; use a temporary file
TMP_CONF=$(mktemp /tmp/onx-vhost-XXXXXX.conf)
trap 'rm -f "${TMP_CONF}"' EXIT

cp "${TEMPLATE_PATH}" "${TMP_CONF}"

# Replace each ${VAR} placeholder. sed delimiter is | to avoid / conflicts.
sed_replace() {
  local var="$1" val="$2"
  # Escape & and newlines in val for sed replacement string
  local escaped_val
  escaped_val=$(printf '%s' "${val}" | sed 's/[&\\/]/\\&/g; s/$/\\n/' | tr -d '\n' | sed 's/\\n$//')
  sed -i "s|\${${var}}|${escaped_val}|g" "${TMP_CONF}"
}

sed_replace "USERNAME"               "${USERNAME}"
sed_replace "DOMAIN"                 "${DOMAIN}"
sed_replace "DOC_ROOT"               "${DOC_ROOT}"
sed_replace "PHP_VERSION_NODOT"      "${PHP_VERSION_NODOT}"
sed_replace "ALIASES_DIRECTIVES"     "${ALIASES_DIRECTIVES}"
sed_replace "HTTPS_REDIRECT_BLOCK"   "${HTTPS_REDIRECT_BLOCK}"
sed_replace "HTTPS_VHOST_BLOCK"      "${HTTPS_VHOST_BLOCK}"

# Install the rendered config
install -m 0644 "${TMP_CONF}" "${VHOST_PATH}"

# ── apachectl configtest → rollback on failure ───────────────────────────────
if ! apachectl configtest 2>/dev/null; then
  onx_log "apachectl configtest failed — rolling back"
  if [[ -f "${BACKUP_PATH}" ]]; then
    mv "${BACKUP_PATH}" "${VHOST_PATH}"
  else
    rm -f "${VHOST_PATH}"
  fi
  onx_die 4 "apachectl configtest failed; vhost rolled back"
fi

rm -f "${BACKUP_PATH}"

# ── Reload httpd ─────────────────────────────────────────────────────────────
if ! systemctl reload httpd; then
  onx_die 3 "systemctl reload httpd failed"
fi

# ── Success ──────────────────────────────────────────────────────────────────
onx_json_out \
  "vhost_path"  "${VHOST_PATH}" \
  "reloaded"    "true" \
  "ssl_enabled" "${SSL_ENABLED}" \
  "server"      "apache"
