#!/usr/bin/env bash
set -Eeuo pipefail

# A4W Auftrag4Works - Linux-Wartungsmenue
# Fuer Notfaelle auf Serverkonsole/SSH, wenn Login oder Passwort-Reset per Mail nicht verfuegbar ist.

SERVICE_NAME="${A4W_SERVICE_NAME:-a4w}"
DATA_ROOT="${A4W_DATA_ROOT:-/var/lib/a4w}"
BACKUP_ROOT="${A4W_BACKUP_ROOT:-/var/backups/a4w}"
DATA_FILE="${A4W_DATA_FILE:-$DATA_ROOT/a4w-data.json}"
STAMP="$(date +%Y%m%d-%H%M%S)"

need_root() {
  if [[ "${EUID}" -ne 0 ]]; then
    echo "Bitte als root oder mit sudo ausfuehren." >&2
    exit 1
  fi
}

pause() {
  read -r -p "Weiter mit Enter..." _
}

show_status() {
  echo "A4W Wartungsstatus"
  echo "  Dienst:       $SERVICE_NAME"
  echo "  Datenordner:  $DATA_ROOT"
  echo "  Datendatei:   $DATA_FILE"
  echo "  Backupordner: $BACKUP_ROOT"
  echo ""
  systemctl status "$SERVICE_NAME" --no-pager || true
}

show_log() {
  journalctl -u "$SERVICE_NAME" -n 120 --no-pager || true
}

restart_service() {
  systemctl restart "$SERVICE_NAME"
  systemctl status "$SERVICE_NAME" --no-pager || true
}

backup_data() {
  mkdir -p "$BACKUP_ROOT"
  local target="$BACKUP_ROOT/a4w-data-backup-$STAMP.zip"
  if [[ ! -f "$DATA_FILE" ]]; then
    echo "Datendatei nicht gefunden: $DATA_FILE" >&2
    return 1
  fi
  if command -v python3 >/dev/null 2>&1; then
    python3 - "$DATA_ROOT" "$target" <<'PY'
import os, sys, zipfile
data_root, target = sys.argv[1], sys.argv[2]
with zipfile.ZipFile(target, "w", zipfile.ZIP_DEFLATED) as zf:
    for name in ("a4w-data.json", "a4w-license.json", "a4w-secrets.key"):
        path = os.path.join(data_root, name)
        if os.path.isfile(path):
            zf.write(path, f"data/{name}")
    for folder in ("Kundenablage", "Attachments", "uploads"):
        root = os.path.join(data_root, folder)
        if os.path.isdir(root):
            for current, _, files in os.walk(root):
                for file in files:
                    path = os.path.join(current, file)
                    rel = os.path.relpath(path, data_root).replace(os.sep, "/")
                    zf.write(path, f"data/{rel}")
PY
  elif command -v zip >/dev/null 2>&1; then
    (cd "$DATA_ROOT" && zip -qr "$target" a4w-data.json a4w-license.json a4w-secrets.key Kundenablage Attachments uploads 2>/dev/null || true)
  else
    echo "Weder python3 noch zip gefunden." >&2
    return 1
  fi
  echo "Backup erstellt: $target"
}

restore_data() {
  read -r -p "Pfad zur Backup-ZIP: " source_zip
  if [[ ! -f "$source_zip" ]]; then
    echo "ZIP nicht gefunden." >&2
    return 1
  fi
  backup_data
  systemctl stop "$SERVICE_NAME" || true
  python3 - "$source_zip" "$DATA_ROOT" <<'PY'
import os, sys, zipfile
zip_path, data_root = sys.argv[1], sys.argv[2]
allowed = ("data/", "App_Data/")
with zipfile.ZipFile(zip_path) as zf:
    for member in zf.infolist():
        name = member.filename.replace("\\", "/").lstrip("/")
        if not name or name.endswith("/") or not name.startswith(allowed):
            continue
        rel = name.split("/", 1)[1]
        if rel.startswith("DemoBackups/") or rel.startswith("Backups/") or rel.startswith("Updates/") or rel.startswith("Logs/"):
            continue
        target = os.path.normpath(os.path.join(data_root, rel))
        if not target.startswith(os.path.abspath(data_root)):
            raise RuntimeError(f"Unsicherer ZIP-Pfad: {member.filename}")
        os.makedirs(os.path.dirname(target), exist_ok=True)
        with zf.open(member) as src, open(target, "wb") as dst:
            dst.write(src.read())
PY
  systemctl start "$SERVICE_NAME"
  echo "Restore abgeschlossen. Bitte Login pruefen."
}

list_users() {
  python3 - "$DATA_FILE" <<'PY'
import json, sys
with open(sys.argv[1], encoding="utf-8-sig") as f:
    data = json.load(f)
for e in data.get("Employees", []):
    login = (e.get("LoginName") or "").strip()
    password = (e.get("PasswordHash") or "").strip()
    inactive = e.get("IsInactive") or e.get("InactiveFrom")
    if login and password and not inactive:
        marker = "Admin" if e.get("IsMasterUser") else "Benutzer"
        print(f"{login:30} {marker:8} {e.get('Name','')}")
PY
}

reset_password() {
  echo "Aktive Login-Benutzer:"
  list_users
  echo ""
  read -r -p "Loginname fuer Reset: " login
  read -r -s -p "Neues Passwort: " password
  echo ""
  if [[ -z "$login" || -z "$password" ]]; then
    echo "Loginname und Passwort duerfen nicht leer sein." >&2
    return 1
  fi
  backup_data
  python3 - "$DATA_FILE" "$login" "$password" <<'PY'
import base64, hashlib, hmac, json, os, sys
path, login, password = sys.argv[1], sys.argv[2], sys.argv[3]
with open(path, encoding="utf-8-sig") as f:
    data = json.load(f)
target = None
for employee in data.get("Employees", []):
    if (employee.get("LoginName") or "").lower() == login.lower():
        target = employee
        break
if target is None:
    raise SystemExit("Loginname nicht gefunden.")
salt = os.urandom(16)
digest = hashlib.pbkdf2_hmac("sha256", password.encode("utf-8"), salt, 120000, dklen=32)
target["PasswordHash"] = "pbkdf2-sha256$120000$" + base64.b64encode(salt).decode() + "$" + base64.b64encode(digest).decode()
target["IsInactive"] = False
target["InactiveFrom"] = None
target["InactiveReason"] = ""
target["Status"] = target.get("Status") or "Aktiv"
with open(path, "w", encoding="utf-8") as f:
    json.dump(data, f, ensure_ascii=False, indent=2)
print("Passwort wurde zurueckgesetzt fuer:", target.get("LoginName"))
PY
  systemctl restart "$SERVICE_NAME" || true
}

menu() {
  while true; do
    clear || true
    echo "A4W Auftrag4Works - Linux-Wartung"
    echo "==================================="
    echo "1) Status anzeigen"
    echo "2) Dienst neu starten"
    echo "3) Journal anzeigen"
    echo "4) Datensicherung erstellen"
    echo "5) Backup-ZIP zurueckspielen"
    echo "6) Login-Benutzer anzeigen"
    echo "7) Passwort zuruecksetzen"
    echo "0) Beenden"
    echo ""
    read -r -p "Auswahl: " choice
    case "$choice" in
      1) show_status; pause ;;
      2) restart_service; pause ;;
      3) show_log; pause ;;
      4) backup_data; pause ;;
      5) restore_data; pause ;;
      6) list_users; pause ;;
      7) reset_password; pause ;;
      0) exit 0 ;;
      *) echo "Unbekannte Auswahl."; pause ;;
    esac
  done
}

need_root
case "${1:-}" in
  --status) show_status ;;
  --restart) restart_service ;;
  --backup) backup_data ;;
  --users) list_users ;;
  --reset-password) reset_password ;;
  *) menu ;;
esac
