#!/usr/bin/env bash
# onx-ols-vhosts-unified-rewrite (v80.9) — TÜM OLS vhost'larını UNIFIED pattern'e dönüştür
#
# Switch (Nginx/Apache → OLS) sonrasi çağrılır. Müşteri ve sistem subdomain
# vhost'larını v79.9 working pattern ile yeniden yazar:
#   - LSAPI native lsphp82 binary
#   - extUser=apache extGroup=webserver
#   - Shared extprocessor (lsphp82sys / lsphp82panel)
#   - restrained=0
#   - subdomain_type-aware rewrite (autodiscover/autoconfig/webmail/panel)
#
# Idempotent — defalarca çağrılabilir.

set -euo pipefail

VHOST_BASE="/usr/local/lsws/conf/vhosts"
LOG_DIR="/var/log/onoxsoft-system"

mkdir -p "${LOG_DIR}"
chown apache:webserver "${LOG_DIR}" 2>/dev/null
chmod 750 "${LOG_DIR}" 2>/dev/null

# Python ile vhost'ları rewrite
python3 <<'PYEOF'
import os, glob

VHOST_BASE = '/usr/local/lsws/conf/vhosts'
SYS_TYPES = ('webmail.', 'mail.', 'panel.', 'webdisk.', 'autoconfig.', 'autodiscover.')

# v80.9.1: ONOXSOFT PANEL vhost (özel) — onx_ prefix değil, onoxsoft-panel
PANEL_VHOST_DIR = f'{VHOST_BASE}/onoxsoft-panel'
if os.path.isdir(PANEL_VHOST_DIR):
    panel_conf = f'{PANEL_VHOST_DIR}/vhconf.conf'
    panel_config = '''docRoot                   /opt/onoxsoft/public
vhDomain                  panel.onoxsoft.com.tr
enableGzip                1

errorlog $VH_ROOT/logs/error.log {
  useServer               1
  logLevel                ERROR
}
accesslog $VH_ROOT/logs/access.log {
  useServer               0
}

index {
  useServer               0
  indexFiles              index.php
}

scripthandler {
  add                     lsapi:lsphp82panel php
}

extprocessor lsphp82panel {
  type                    lsapi
  address                 uds://tmp/lshttpd/lsphp82-panel.sock
  maxConns                10
  env                     LSAPI_CHILDREN=10
  initTimeout             60
  retryTimeout            0
  persistConn             1
  pcKeepAliveTimeout      60
  respBuffer              0
  autoStart               1
  path                    /usr/local/lsws/lsphp82/bin/lsphp
  extUser                 apache
  extGroup                webserver
  memSoftLimit            512M
  memHardLimit            1024M
}

context / {
  location                /opt/onoxsoft/public
  scripthandler {
    add                   lsapi:lsphp82panel php
  }
  allowBrowse             1
  indexFiles              index.php
  rewrite {
    enable                1
    rules                 <<<END_RULES
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php [L]
END_RULES
  }
}

# v3.35: phpMyAdmin /phpmyadmin (+ /phpMyAdmin alias) context.
# Apache panel vhost'unda Alias var, OLS'de context olmadığı için 404 alınıyordu.
# Ayrı extprocessor (lsphp82pma) kullanılır — panel pool ile çakışmaz.
context /phpmyadmin {
  location                /usr/share/phpMyAdmin
  allowBrowse             1
  indexFiles              index.php
  scripthandler {
    add                   lsapi:lsphp82pma php
  }
  rewrite {
    enable                0
  }
}

context /phpMyAdmin {
  location                /usr/share/phpMyAdmin
  allowBrowse             1
  indexFiles              index.php
  scripthandler {
    add                   lsapi:lsphp82pma php
  }
}

extprocessor lsphp82pma {
  type                    lsapi
  address                 uds://tmp/lshttpd/lsphp82-pma.sock
  maxConns                5
  env                     LSAPI_CHILDREN=5
  initTimeout             60
  retryTimeout            0
  persistConn             1
  pcKeepAliveTimeout      60
  respBuffer              0
  autoStart               1
  path                    /usr/local/lsws/lsphp82/bin/lsphp
  extUser                 apache
  extGroup                webserver
  memSoftLimit            256M
  memHardLimit            512M
}

vhssl {
  keyFile                 /etc/onoxsoft/ssl/panel.onoxsoft.com.tr.key
  certFile                /etc/onoxsoft/ssl/panel.onoxsoft.com.tr.fullchain
  certChain               1
  sslProtocol             24
  enableECDHE             1
  renegProtection         1
  sslSessionCache         1
}
'''
    with open(panel_conf, 'w') as f:
        f.write(panel_config)
    print("  ✓ onoxsoft-panel (özel — LSAPI native + lsphp82-panel.sock)")

count = 0
for vh_dir in sorted(glob.glob(f'{VHOST_BASE}/onx_*/')):
    vh_name = os.path.basename(vh_dir.rstrip('/'))
    vh_conf = f'{vh_dir}vhconf.conf'
    if not os.path.exists(vh_conf):
        continue

    user, _, domain = vh_name.partition('-')
    docroot = ('/usr/share/roundcubemail'      if any(domain.startswith(t) for t in ('webmail.', 'mail.')) else
               '/usr/local/onoxsoft/autodiscover' if any(domain.startswith(t) for t in ('autoconfig.', 'autodiscover.')) else
               '/var/www/html'                    if any(domain.startswith(t) for t in ('panel.', 'webdisk.')) else
               f'/home/users/{user}/public_html')

    # Cert lookup (acme.sh ECC > RSA > LE)
    cert = key = ''
    parent = '.'.join(domain.split('.')[-3:]) if domain.count('.') >= 2 else domain
    for d in (domain, parent):
        for c, k in [
            (f'/root/.acme.sh/{d}_ecc/fullchain.cer', f'/root/.acme.sh/{d}_ecc/{d}.key'),
            (f'/root/.acme.sh/{d}/fullchain.cer', f'/root/.acme.sh/{d}/{d}.key'),
            (f'/etc/letsencrypt/live/{d}/fullchain.pem', f'/etc/letsencrypt/live/{d}/privkey.pem'),
        ]:
            if os.path.isfile(c) and os.path.isfile(k):
                cert, key = c, k
                break
        if cert: break

    ssl_block = (f'\nvhssl {{\n  keyFile {key}\n  certFile {cert}\n  certChain 1\n'
                 f'  sslProtocol 24\n  enableECDHE 1\n  renegProtection 1\n  sslSessionCache 1\n}}') if cert else ''

    # subdomain_type-aware rewrite + indexFiles
    indexes = 'index.php, index.html'
    if domain.startswith('autodiscover.'):
        rewrite = 'RewriteRule ^/?[Aa]utodiscover/[Aa]utodiscover\\.xml$ /autodiscover.xml.php [L]'
        indexes = 'autodiscover.xml.php, index.php'
    elif domain.startswith('autoconfig.'):
        rewrite = 'RewriteRule ^/?mail/config-v1\\.1\\.xml$ /thunderbird.xml.php [L]\n    RewriteRule ^/?\\.well-known/autoconfig/mail/config-v1\\.1\\.xml$ /thunderbird.xml.php [L]'
        indexes = 'thunderbird.xml.php, index.php'
    else:
        # v3.44 FIX: SUSPEND MARKER prepend — askıdaysa branded index.html'i internal serve et.
        # ESKİ: `R=503` flag external REDIRECT yapıyordu → browser Location header takip
        # etmeye çalışıyor, 503 status redirect'i engelliyor → CYCLIC LOOP → OLS default
        # 503 sayfası görünüyordu (branded suspended.html serve EDİLMİYORDU).
        # YENİ: `R=` flag KALDIRILDI → [L] ile INTERNAL rewrite → HTTP 200 +
        # branded suspended.html (onx-default-page-deploy tarafından deploy edilmiş)
        # serve ediliyor. cPanel/WHM standart davranışı.
        suspend_marker = f'/usr/local/lsws/conf/vhosts/{vh_name}/.onx-suspended'
        rewrite = (f'RewriteCond {suspend_marker} -f\n'
                   '    RewriteCond %{REQUEST_URI} !^/index\\.html$\n'
                   '    RewriteCond %{REQUEST_URI} !^/__onx-health$\n'
                   '    RewriteRule ^(.*)$ /index.html [L]\n'
                   '    RewriteCond %{REQUEST_FILENAME} !-f\n'
                   '    RewriteCond %{REQUEST_FILENAME} !-d\n'
                   '    RewriteRule ^(.*)$ /index.php [L]')

    # panel.X için index.php redirect generate (yoksa)
    if domain.startswith('panel.') and not os.path.exists(f'{docroot}/index.php'):
        os.makedirs(docroot, exist_ok=True)
        with open(f'{docroot}/index.php', 'w') as f:
            f.write("<?php header('Location: https://panel.onoxsoft.com.tr:666/customer/dashboard', true, 302);\n")
        os.system(f'chown apache:webserver {docroot}/index.php')

    # v86.1: docroot izinleri + handler dispatch (system subdomain vs customer real domain)
    # v86.2 FIX: OLS scripthandler'ı vhost-level'dan context'e INHERIT ETMIYOR
    # (özellikle FCGI tipinde) — handler dispatch'i context içine de KOPYALA, yoksa
    # tüm .php request'leri "MIME type [application/x-httpd-php] does not allow
    # serving as static file, access denied" 403 alır. Production bug bisaglik.com /
    # cca.leafport.com.tr (v86.2 öncesi tespit).
    is_sys = any(domain.startswith(t) for t in SYS_TYPES)
    if is_sys:
        # System subdomain (webmail/mail/panel/webdisk/autoconfig/autodiscover) — shared LSAPI
        if os.path.isdir(docroot):
            os.system(f'chown -R apache:webserver "{docroot}" 2>/dev/null')
            os.system(f'chmod -R u+rwX,g+rX,o+rX "{docroot}" 2>/dev/null')
        # Vhost-level: scripthandler + extprocessor (extprocessor SADECE vhost-level)
        handler_block = '''scripthandler {
  add                     lsapi:lsphp82sys php
}

extprocessor lsphp82sys {
  type                    lsapi
  address                 uds://tmp/lshttpd/lsphp82-sys.sock
  maxConns                10
  env                     LSAPI_CHILDREN=10
  initTimeout             60
  retryTimeout            0
  persistConn             1
  pcKeepAliveTimeout      60
  respBuffer              0
  autoStart               1
  path                    /usr/local/lsws/lsphp82/bin/lsphp
  extUser                 apache
  extGroup                webserver
}'''
        # Context-level: scripthandler TEKRARI (v86.2 inheritance fix, 2-space indent)
        inner_dispatch = '''  scripthandler {
    add                     lsapi:lsphp82sys php
  }'''
    else:
        # v3.43 PER-CUSTOMER LSAPI (cgroup isolation):
        # Eski v3.32 shared lsphp82sys → tüm customer'lar aynı backend (isolation yok).
        # Şimdi her customer için ayrı LSAPI extprocessor (onx_<user>_lsphp82):
        #   - extUser/extGroup = onx_<user> → systemd-user cgroup slice'a girer
        #   - memSoftLimit 256M / memHardLimit 512M (PHP workload makul ceiling)
        #   - procSoftLimit 50 / procHardLimit 100 (fork bomb koruması)
        #   - autoStart 2 (cold 2 child, demand'a göre LSAPI_CHILDREN=5)
        #
        # Önkoşul: onx_<user> Linux user mevcut olmalı (onx-user-add yaratır).
        # Yoksa fallback shared lsphp82sys (eski v3.32 davranışı korunur).
        if os.path.isdir(docroot):
            # docroot chown: user:onx_<user> (extGroup=onx_<user> ile uyumlu)
            # webserver group g+rX statik dosyalara erişim sürer
            os.system(f'chown -R {user}:{user} "{docroot}" 2>/dev/null')
            os.system(f'chgrp -R webserver "{docroot}" 2>/dev/null')
            os.system(f'chmod -R u+rwX,g+rX,o+rX "{docroot}" 2>/dev/null')

        # v3.44 FIX: User check + gerçek primary group resolve
        # ESKİ: getent group {user} check ediyordu ama ONOXSOFT user-add primary group
        # `onoxsoft-users` (shared) atıyor, customer-spesifik group YOK → fallback'e düşüyordu.
        # YENI: id -u {user} ile user varlığı check + id -gn {user} ile gerçek primary group al.
        # extGroup = gerçek primary group (onoxsoft-users), extUser = customer username.
        # Cgroup isolation tam değil (shared onoxsoft-users) ama LSAPI worker user farklı,
        # her customer'ın PHP süreçleri uid bazında ayrı → kısmi isolation.
        user_exists = os.system(f'id -u {user} >/dev/null 2>&1') == 0
        try:
            actual_pri_group = os.popen(f'id -gn {user} 2>/dev/null').read().strip() if user_exists else ''
        except Exception:
            actual_pri_group = ''
        if not actual_pri_group:
            actual_pri_group = 'onoxsoft-users'  # safe fallback

        if user_exists:
            # Per-customer LSAPI
            handler_block = f'''scripthandler {{
  add                     lsapi:{user}_lsphp82 php
}}

extprocessor {user}_lsphp82 {{
  type                    lsapi
  address                 uds://tmp/lshttpd/{user}_lsphp82.sock
  maxConns                10
  env                     LSAPI_CHILDREN=5
  initTimeout             60
  retryTimeout            0
  persistConn             1
  pcKeepAliveTimeout      60
  respBuffer              0
  autoStart               2
  path                    /usr/local/lsws/lsphp82/bin/lsphp
  extUser                 {user}
  extGroup                {actual_pri_group}
  memSoftLimit            256M
  memHardLimit            512M
  procSoftLimit           50
  procHardLimit           100
}}'''
            inner_dispatch = f'''  scripthandler {{
    add                     lsapi:{user}_lsphp82 php
  }}'''
        else:
            # Fallback (user group yok) — shared lsphp82sys (v3.32 davranışı)
            handler_block = '''scripthandler {
  add                     lsapi:lsphp82sys php
}

extprocessor lsphp82sys {
  type                    lsapi
  address                 uds://tmp/lshttpd/lsphp82-sys.sock
  maxConns                10
  env                     LSAPI_CHILDREN=10
  initTimeout             60
  retryTimeout            0
  persistConn             1
  pcKeepAliveTimeout      60
  respBuffer              0
  autoStart               1
  path                    /usr/local/lsws/lsphp82/bin/lsphp
  extUser                 apache
  extGroup                webserver
}'''
            inner_dispatch = '''  scripthandler {
    add                     lsapi:lsphp82sys php
  }'''

    config = f'''# ONOX-managed OLS vhost (v86.2 — context-level scripthandler inheritance fix)
docRoot                   {docroot}
vhDomain                  {domain}
vhAliases                 www.{domain}
enableGzip                1

errorlog /var/log/onoxsoft-system/{domain}-error.log {{
  useServer               1
  logLevel                ERROR
}}
accesslog /var/log/onoxsoft-system/{domain}-access.log {{
  useServer               0
}}

index {{
  useServer               0
  indexFiles              {indexes}
}}

{handler_block}

context /.well-known/acme-challenge {{
  location                /var/lib/letsencrypt/.well-known/acme-challenge
  allowBrowse             1
  indexFiles              -
  rewrite {{
    enable                0
  }}
  accessControl {{
    allow                 *
  }}
  enableExpires           0
  expires                 -1
}}

context / {{
  location                {docroot}
{inner_dispatch}
  allowBrowse             1
  indexFiles              {indexes}
  rewrite {{
    enable                1
    rules                 <<<END_RULES
    {rewrite}
END_RULES
  }}
}}
{ssl_block}
'''
    with open(vh_conf, 'w') as f:
        f.write(config)
    count += 1
    print(f"  ✓ {vh_name}")

# httpd_config.conf'ta virtualhost block'larında restrained=0 + user=apache + group=webserver
import re
CONF = '/usr/local/lsws/conf/httpd_config.conf'
with open(CONF) as f:
    content = f.read()

modified = 0
def fix_block(m):
    global modified
    head = m.group(1)
    name = m.group(2)
    if not name.startswith('onx_'):
        return m.group(0)
    modified += 1
    return (head + f'''
  vhRoot                  /usr/local/lsws/conf/vhosts/{name}/
  configFile              /usr/local/lsws/conf/vhosts/{name}/vhconf.conf
  allowSymbolLink         1
  enableScript            1
  restrained              0
  setUIDMode              2
  user                    apache
  group                   webserver
}}''')

pattern = re.compile(r'(virtualhost\s+(onx_\w+-[^\s{]+)\s*\{)[^}]*?\n\}', re.DOTALL)
new_content = pattern.sub(fix_block, content)
if modified > 0:
    os.rename(CONF, CONF + '.bak.v80.9')
    with open(CONF, 'w') as f:
        f.write(new_content)
    print(f"\n✓ {modified} virtualhost block standardized (apache:webserver restrained=0)")

print(f"\n✓ TOTAL: {count} vhost rewritten")
PYEOF

# Worker cold restart — yeni LSAPI extprocessor + virtualhost ayarları için şart
pkill -9 lsphp 2>/dev/null || true
sleep 1
rm -f /tmp/lshttpd/lsphp*.sock 2>/dev/null || true
systemctl restart lsws
sleep 3

echo "✓ lsws restart + LSAPI worker pool refresh"
