#!/bin/bash
# ===========================================================================
# meyton-sync Target / API — Installations-Skript
# Unterstützte Systeme: Debian, Ubuntu
# Muss als root ausgeführt werden.
# ===========================================================================
set -euo pipefail

# ---------------------------------------------------------------------------
# Hilfsfunktionen
# ---------------------------------------------------------------------------

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

err()     { echo -e "${RED}FEHLER: $*${NC}" >&2; exit 1; }
info()    { echo -e "${GREEN}[OK]${NC} $*"; }
warn()    { echo -e "${YELLOW}[WARN]${NC} $*"; }
section() { echo; echo -e "${CYAN}${BOLD}=== $* ===${NC}"; echo; }

ask() {
    # /dev/tty nötig: Funktion wird via $() aufgerufen,
    # stdout ist captured — Prompt und read müssen direkt ans Terminal.
    local label="$1" default="$2"
    echo -ne "  $label [$default]: " > /dev/tty
    read -r _INPUT < /dev/tty
    echo "${_INPUT:-$default}"
}

ask_secret() {
    local label="$1" default="$2"
    echo -ne "  $label [$default]: " > /dev/tty
    read -rs _INPUT < /dev/tty
    echo > /dev/tty
    echo "${_INPUT:-$default}"
}

# ---------------------------------------------------------------------------
# Voraussetzungen prüfen
# ---------------------------------------------------------------------------

[ "$(id -u)" -eq 0 ] || err "Dieses Skript muss als root ausgeführt werden."

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

[ -f "$SCRIPT_DIR/target.py" ] || \
    err "target.py nicht gefunden. Skript muss aus dem target/-Verzeichnis ausgeführt werden."

# ---------------------------------------------------------------------------
# Betriebssystem prüfen (nur Debian/Ubuntu)
# ---------------------------------------------------------------------------

# shellcheck source=/dev/null
. /etc/os-release
OS_ID="${ID:-unknown}"
OS_LIKE="${ID_LIKE:-}"

if [[ "$OS_ID" != "ubuntu" ]] && [[ "$OS_ID" != "debian" ]] && [[ "$OS_LIKE" != *debian* ]]; then
    err "Nicht unterstütztes Betriebssystem: $OS_ID\n  Unterstützt: Debian, Ubuntu"
fi

# ---------------------------------------------------------------------------
# Aktuelle Konfigurationswerte als Defaults lesen
# ---------------------------------------------------------------------------

conf_val() {
    local key="$1" fallback="$2"
    local val
    val=$(grep -E "^${key}\s*=" "$SCRIPT_DIR/target.conf" 2>/dev/null \
          | head -1 | sed 's/^[^=]*=\s*//' | tr -d '\r')
    echo "${val:-$fallback}"
}

DEF_DB_HOST=$(conf_val "host"                 "localhost")
DEF_DB_PORT=$(conf_val "port"                 "3306")
DEF_DB_USER=$(conf_val "user"                 "meyton")
DEF_DB_PASS=$(conf_val "password"             "mc4hct")
DEF_DB_NAME=$(conf_val "database"             "SSMDB2c")
DEF_OWN_TOKEN=$(conf_val "own_token"          \
    "$(python3 -c 'import secrets; print(secrets.token_hex(32))')")
DEF_SOURCE_TOKEN=$(conf_val "source_token"    \
    "$(python3 -c 'import secrets; print(secrets.token_hex(32))')")
DEF_SECRET_KEY=$(conf_val "secret_key"        \
    "$(python3 -c 'import secrets; print(secrets.token_hex(32))')")
DEF_TOKEN_EXPIRE=$(conf_val "token_expire_minutes" "60")

# Apache: HTTPS-VirtualHost suchen
DEF_APACHE_CONF=""
if [ ! -f "$DEF_APACHE_CONF" ]; then
    # Ersten HTTPS-VirtualHost in sites-enabled als Fallback
    DEF_APACHE_CONF=$(find /etc/apache2/sites-enabled/ -name "*-le-ssl.conf" \
                      | head -1 || echo "/etc/apache2/sites-enabled/default-ssl.conf")
fi

# ---------------------------------------------------------------------------
# Konfiguration interaktiv abfragen
# ---------------------------------------------------------------------------

section "meyton-sync Target / API — Installation"
echo "  System  : $PRETTY_NAME"
echo
echo "  Alle Standardwerte können mit Enter übernommen werden."
echo "  Passwörter werden nicht angezeigt während der Eingabe."

section "Datenbankverbindung (SSMDB2c auf diesem Server)"
echo "  Diese Zugangsdaten werden in target.conf gespeichert und von"
echo "  target.py zur Laufzeit genutzt. Ein höher privilegierter User"
echo "  (root) wird separat nur für die Einrichtung der Datenbank abgefragt."
echo
DB_HOST=$(ask        "Host"                              "$DEF_DB_HOST")
DB_PORT=$(ask        "Port"                              "$DEF_DB_PORT")
DB_NAME=$(ask        "Datenbank"                        "$DEF_DB_NAME")
DB_USER=$(ask        "Laufzeit-User (wird angelegt)"    "$DEF_DB_USER")
DB_PASS=$(ask_secret "Laufzeit-Passwort (wird gesetzt)" "$DEF_DB_PASS")

section "Synchronisierung (Token-Austausch mit Source-Server)"
echo "  Die folgenden Tokens müssen mit der Source-Konfiguration übereinstimmen:"
OWN_TOKEN=$(ask    "  Eigener Token (Target)"       "$DEF_OWN_TOKEN")
SOURCE_TOKEN=$(ask "  Token des Source-Servers"     "$DEF_SOURCE_TOKEN")

section "API-Konfiguration"
SECRET_KEY=$(ask     "JWT Secret Key"               "$DEF_SECRET_KEY")
TOKEN_EXPIRE=$(ask   "Token Gültigkeit (Minuten)"   "$DEF_TOKEN_EXPIRE")

section "Apache-Konfiguration"
echo "  Der Reverse-Proxy-Block wird in die angegebene Datei eingefügt."
APACHE_CONF=$(ask "Pfad zur HTTPS-VirtualHost-Konfiguration" "$DEF_APACHE_CONF")

# ---------------------------------------------------------------------------
# Zusammenfassung und Bestätigung
# ---------------------------------------------------------------------------

section "Zusammenfassung"
echo "  Datenbank     : $DB_USER@$DB_HOST:$DB_PORT/$DB_NAME"
echo "  Token Ablauf  : ${TOKEN_EXPIRE} Minuten"
echo "  Installiert   : /opt/meyton-sync/target/"
echo "  Apache-Conf   : $APACHE_CONF"
echo "  Swagger UI    : https://www.mydomain.de/meyton/docs"
echo
read -rp "Installation starten? [J/n]: " _CONFIRM
[[ "${_CONFIRM,,}" == "n" ]] && { echo "Abgebrochen."; exit 0; }

# ---------------------------------------------------------------------------
# Pakete installieren
# ---------------------------------------------------------------------------

section "Pakete installieren"

info "Installiere via apt-get..."
apt-get update -q
apt-get install -y \
    python3 \
    python3-fastapi \
    python3-uvicorn \
    python3-multipart \
    python3-passlib \
    python3-bcrypt \
    python3-jwt \
    python3-pymysql \
    mariadb-client

info "Pakete installiert."

# ---------------------------------------------------------------------------
# Datenbank anlegen
# ---------------------------------------------------------------------------

section "Datenbank vorbereiten"

_mysql_cmd() {
    # Wrapper: versucht zuerst Socket-Auth (root ohne Passwort),
    # fragt dann einmalig nach dem MariaDB/MySQL-Root-Passwort.
    mysql --defaults-extra-file=<(printf '[client]\nuser=root\n') \
          "$@" 2>/dev/null \
    || mysql --defaults-extra-file=<(printf '[client]\nuser=root\npassword=%s\n' \
                                     "$_MYSQL_ROOT_PASS") "$@"
}

# Verbindungstest — Socket-Auth (root ohne Passwort, typisch auf Debian/Ubuntu)
_MYSQL_ROOT_PASS=""
info "Teste Datenbankverbindung als root (Socket-Auth)..."
if ! mysql -u root -e "SELECT 1" > /dev/null 2>&1; then
    warn "Socket-Auth fehlgeschlagen. Bitte das MariaDB/MySQL root-Passwort eingeben."
    echo "  (Dieses Passwort wird nur für die Einrichtung verwendet und nicht gespeichert.)"
    echo -ne "  MariaDB/MySQL root-Passwort: " > /dev/tty
    read -rs _MYSQL_ROOT_PASS < /dev/tty
    echo > /dev/tty
    mysql -u root -p"$_MYSQL_ROOT_PASS" -e "SELECT 1" > /dev/null 2>&1 \
        || err "Verbindung zur Datenbank fehlgeschlagen. Root-Passwort prüfen."
    info "Datenbankverbindung erfolgreich (mit Passwort)."
else
    info "Datenbankverbindung erfolgreich (Socket-Auth)."
fi

_MYSQL="mysql -u root"
[ -n "$_MYSQL_ROOT_PASS" ] && _MYSQL="mysql -u root -p${_MYSQL_ROOT_PASS}"

# Datenbank erstellen falls nicht vorhanden
if ! $_MYSQL -e "USE \`${DB_NAME}\`" > /dev/null 2>&1; then
    $_MYSQL << SQL
CREATE DATABASE \`${DB_NAME}\`
    CHARACTER SET utf8mb3
    COLLATE utf8mb3_unicode_ci;
SQL
    info "Datenbank '${DB_NAME}' erstellt."
else
    info "Datenbank '${DB_NAME}' bereits vorhanden."
fi

# Datenbankbenutzer anlegen und Rechte vergeben
$_MYSQL << SQL
CREATE USER IF NOT EXISTS '${DB_USER}'@'localhost' IDENTIFIED BY '${DB_PASS}';
ALTER USER '${DB_USER}'@'localhost' IDENTIFIED BY '${DB_PASS}';
GRANT ALL PRIVILEGES ON \`${DB_NAME}\`.* TO '${DB_USER}'@'localhost';
FLUSH PRIVILEGES;
SQL
info "Benutzer '${DB_USER}' und Berechtigungen auf '${DB_NAME}' gesetzt."

# ---------------------------------------------------------------------------
# Apache-Module aktivieren
# ---------------------------------------------------------------------------

section "Apache-Module aktivieren"

a2enmod proxy proxy_http headers
info "Module proxy, proxy_http, headers aktiviert."

# ---------------------------------------------------------------------------
# Dateien installieren
# ---------------------------------------------------------------------------

section "Dateien installieren"

INSTALL_DIR="/opt/meyton-sync/target"
mkdir -p "$INSTALL_DIR"

if [ -f "$INSTALL_DIR/target.conf" ]; then
    cp "$INSTALL_DIR/target.conf" "$INSTALL_DIR/target.conf.bak"
    warn "Bestehende Konfiguration gesichert: target.conf.bak"
fi

cp "$SCRIPT_DIR/target.py" "$INSTALL_DIR/"
info "target.py kopiert nach $INSTALL_DIR"

# ---------------------------------------------------------------------------
# Konfigurationsdatei schreiben
# ---------------------------------------------------------------------------

cat > "$INSTALL_DIR/target.conf" << EOF
[database]
host = ${DB_HOST}
port = ${DB_PORT}
user = ${DB_USER}
password = ${DB_PASS}
database = ${DB_NAME}

[sync]
own_token = ${OWN_TOKEN}
source_token = ${SOURCE_TOKEN}

[api]
; Zufälliger langer String für JWT-Signierung
secret_key = ${SECRET_KEY}
token_expire_minutes = ${TOKEN_EXPIRE}

[logging]
level = INFO
file = target.log
EOF

info "target.conf geschrieben."

# ---------------------------------------------------------------------------
# Berechtigungen setzen
# ---------------------------------------------------------------------------

chown -R www-data:www-data "$INSTALL_DIR"
chmod 750 "$INSTALL_DIR"
chmod 640 "$INSTALL_DIR/target.conf"
chmod 750 "$INSTALL_DIR/target.py"
info "Berechtigungen gesetzt (owner: www-data)."

# ---------------------------------------------------------------------------
# Systemd-Service installieren
# ---------------------------------------------------------------------------

section "Systemd-Service installieren"

UVICORN_BIN="$(which python3) -m uvicorn"

cat > /etc/systemd/system/meyton-sync-target.service << EOF
[Unit]
Description=meyton-sync Target (FastAPI)
After=network.target mariadb.service mysql.service
Wants=mariadb.service mysql.service

[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=${INSTALL_DIR}

ExecStart=${UVICORN_BIN} target:app --host 127.0.0.1 --port 8000

Restart=on-failure
RestartSec=5

StandardOutput=journal
StandardError=journal
SyslogIdentifier=meyton-sync-target

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable meyton-sync-target

if systemctl is-active --quiet meyton-sync-target; then
    systemctl restart meyton-sync-target
    info "Service neu gestartet."
else
    systemctl start meyton-sync-target
    info "Service gestartet."
fi

# ---------------------------------------------------------------------------
# Apache-Konfiguration aktualisieren
# ---------------------------------------------------------------------------

section "Apache-Konfiguration aktualisieren"

if [ ! -f "$APACHE_CONF" ]; then
    warn "Apache-Konfigurationsdatei nicht gefunden: $APACHE_CONF"
    warn "Reverse-Proxy bitte manuell eintragen. Vorlage: $SCRIPT_DIR/meyton-sync-apache.conf"
else
    # Python übernimmt die Dateimanipulation (zuverlässiger als sed bei mehrzeiligen Blöcken)
    export MEYTON_APACHE_CONF="$APACHE_CONF"
    python3 << 'PYEOF'
import os, re, sys

apache_conf = os.environ['MEYTON_APACHE_CONF']

proxy_block = """
    # --- meyton-sync Reverse Proxy ---
    ProxyPass        /meyton/  http://127.0.0.1:8000/
    ProxyPassReverse /meyton/  http://127.0.0.1:8000/

    <Location /meyton/>
        ProxyPreserveHost On
        RequestHeader set X-Forwarded-Proto   "https"
        RequestHeader set X-Forwarded-Prefix  "/meyton"
    </Location>
    # --- Ende meyton-sync ---
"""

try:
    with open(apache_conf) as f:
        content = f.read()

    if 'meyton-sync' in content:
        print('[OK] Apache-Konfiguration enthält bereits meyton-sync Eintrag.')
        sys.exit(0)

    # Gezielt den HTTPS-VirtualHost (Port 443) finden.
    # Strategie: alle <VirtualHost ...> Blöcke durchsuchen und den ersten
    # mit :443 nehmen. Dann dessen schließendes </VirtualHost> bestimmen.
    vhost_start_re = re.compile(r'<VirtualHost\s[^>]*:443[^>]*>', re.IGNORECASE)
    match = vhost_start_re.search(content)

    if not match:
        print('FEHLER: Kein VirtualHost mit Port 443 gefunden.', file=sys.stderr)
        print('        Bitte Reverse-Proxy manuell eintragen.', file=sys.stderr)
        sys.exit(1)

    # Ab dem Treffer das zugehörige </VirtualHost> suchen
    # (einfache Zählung von öffnenden/schließenden Tags für korrekte Verschachtelung)
    search_from = match.end()
    depth = 1
    pos = search_from
    open_re  = re.compile(r'<VirtualHost\b',  re.IGNORECASE)
    close_re = re.compile(r'</VirtualHost\s*>', re.IGNORECASE)

    while depth > 0 and pos < len(content):
        o = open_re.search(content, pos)
        c = close_re.search(content, pos)
        if c is None:
            print('FEHLER: Kein schließendes </VirtualHost> gefunden.', file=sys.stderr)
            sys.exit(1)
        if o and o.start() < c.start():
            depth += 1
            pos = o.end()
        else:
            depth -= 1
            if depth == 0:
                insert_at = c.start()   # Einfügen VOR dem schließenden Tag
            pos = c.end()

    # Backup erstellen
    with open(apache_conf + '.bak', 'w') as f:
        f.write(content)

    # Proxy-Block in den 443-VirtualHost einfügen
    new_content = content[:insert_at] + proxy_block + content[insert_at:]
    with open(apache_conf, 'w') as f:
        f.write(new_content)

    print('[OK] Proxy-Block in HTTPS-VirtualHost (Port 443) eingefügt.')
    print(f'[OK] Backup erstellt: {apache_conf}.bak')

except Exception as e:
    print(f'FEHLER: {e}', file=sys.stderr)
    sys.exit(1)
PYEOF

    # Apache-Konfiguration testen und neu laden
    if apache2ctl configtest 2>/dev/null; then
        systemctl reload apache2
        info "Apache erfolgreich neu geladen."
    else
        warn "Apache-Konfigurationstest fehlgeschlagen."
        warn "Bitte manuell prüfen: apache2ctl configtest"
    fi
fi

# ---------------------------------------------------------------------------
# Abschluss
# ---------------------------------------------------------------------------

section "Installation erfolgreich abgeschlossen"
echo -e "  ${BOLD}Installationsverzeichnis${NC}  : $INSTALL_DIR"
echo -e "  ${BOLD}Konfigurationsdatei${NC}       : $INSTALL_DIR/target.conf"
echo -e "  ${BOLD}Service-Status${NC}            : $(systemctl is-active meyton-sync-target)"
echo -e "  ${BOLD}Swagger UI${NC}                : https://www.mydomain.de/meyton/docs"
echo
echo "  Logs anzeigen:"
echo "    journalctl -u meyton-sync-target -f"
echo
echo "  Service steuern:"
echo "    systemctl start|stop|restart|status meyton-sync-target"
echo
