#!/usr/bin/env python3
"""
admin_cli.py  –  EEG-Assistent · Kommandozeilen-Admin

Beispiele:
  python admin_cli.py create-admin
  python admin_cli.py create-account --customer "Musterfirma GmbH" \\
         --email info@musterfirma.at --device "Büro Laptop Anna" --tokens 100
  python admin_cli.py list
  python admin_cli.py list --include-disabled
  python admin_cli.py adjust-tokens --uid EEGA-1234-5678-ABCD --delta +50 \\
         --reason "Nachkauf"
  python admin_cli.py disable --uid EEGA-1234-5678-ABCD
  python admin_cli.py enable  --uid EEGA-1234-5678-ABCD
  python admin_cli.py log     --uid EEGA-1234-5678-ABCD --limit 50
  python admin_cli.py packages
  python admin_cli.py backup  # manuelles Backup
"""

from __future__ import annotations

import argparse
import getpass
import json
import os
import sys
from datetime import datetime

# Sicherstellen, dass das Modul aus demselben Verzeichnis gefunden wird
HERE = os.path.dirname(os.path.abspath(__file__))
if HERE not in sys.path:
    sys.path.insert(0, HERE)

import licensing  # noqa: E402


def _fmt_date(ts: str | None) -> str:
    if not ts:
        return "—"
    try:
        return datetime.fromisoformat(ts).strftime("%d.%m.%Y %H:%M")
    except Exception:
        return ts


def _fmt_days_left(expires: str | None) -> str:
    if not expires:
        return "—"
    try:
        d = datetime.fromisoformat(expires)
        # naive vs. aware – licensing speichert aware, daher umrechnen
        from datetime import timezone
        now = datetime.now(timezone.utc)
        delta = d - now
        if delta.days < 0:
            return "abgelaufen"
        return f"{delta.days} Tage"
    except Exception:
        return "?"


def cmd_create_admin(args) -> int:
    username = args.username or input("Admin-Username: ").strip()
    pw1 = getpass.getpass("Passwort (min. 8 Zeichen): ")
    pw2 = getpass.getpass("Passwort wiederholen: ")
    if pw1 != pw2:
        print("❌ Passwörter stimmen nicht überein.")
        return 2
    try:
        licensing.create_admin(username, pw1)
    except Exception as e:
        print(f"❌ {e}")
        return 1
    print(f"✅ Admin '{username}' angelegt.")
    return 0


def cmd_create_account(args) -> int:
    try:
        uid = licensing.create_account(
            customer_name=args.customer,
            customer_email=args.email,
            device_name=args.device,
            initial_tokens=args.tokens,
            notes=args.notes,
            admin_user=args.admin or "cli",
        )
    except Exception as e:
        print(f"❌ {e}")
        return 1
    print()
    print("═" * 60)
    print(f"  ✅ Neues Konto angelegt")
    print("═" * 60)
    print(f"  Kunde:       {args.customer}")
    if args.email:
        print(f"  E-Mail:      {args.email}")
    if args.device:
        print(f"  Gerät:       {args.device}")
    print(f"  Start-Token: {args.tokens}")
    print()
    print(f"  ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓")
    print(f"  ┃  {uid}  ┃")
    print(f"  ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛")
    print()
    print("  ⚠ Diese UID wird nur jetzt im Klartext angezeigt. Notieren!")
    print("═" * 60)
    return 0


def cmd_list(args) -> int:
    rows = licensing.list_accounts(include_disabled=args.include_disabled)
    if not rows:
        print("(keine Konten vorhanden)")
        return 0

    # Spaltenbreiten
    print()
    print(f"{'UID':21s}  {'Kunde':24s}  {'Gerät':20s}  "
          f"{'Tokens':>10s}  {'Rest':>6s}  {'Status':9s}  "
          f"{'Erstnutzung':16s}  {'Rest':>12s}")
    print("─" * 140)
    for a in rows:
        uid_masked = f"{a['uid'][:9]}…{a['uid'][-4:]}"
        print(
            f"{uid_masked:21s}  "
            f"{(a['customer_name'] or '')[:24]:24s}  "
            f"{(a['device_name'] or '—')[:20]:20s}  "
            f"{a['initial_tokens']:>10d}  "
            f"{a['remaining_tokens']:>6d}  "
            f"{a['status']:9s}  "
            f"{_fmt_date(a['first_used_at']):16s}  "
            f"{_fmt_days_left(a['expires_at']):>12s}"
        )
        if a["fingerprint_mismatches"]:
            print(f"  ⚠ {a['fingerprint_mismatches']} Fingerprint-Mismatches")
    print()
    return 0


def cmd_adjust(args) -> int:
    try:
        res = licensing.adjust_tokens(
            uid=args.uid, delta=args.delta, reason=args.reason,
            admin_user=args.admin or "cli",
        )
    except Exception as e:
        print(f"❌ {e}")
        return 1
    print(f"✅ Neuer Tokenstand für {args.uid}: {res['new_balance']}")
    return 0


def cmd_set_status(args, status: str) -> int:
    try:
        licensing.set_status(args.uid, status, admin_user=args.admin or "cli")
    except Exception as e:
        print(f"❌ {e}")
        return 1
    print(f"✅ Status von {args.uid} → {status}")
    return 0


def cmd_log(args) -> int:
    entries = licensing.get_usage_log(uid=args.uid, limit=args.limit)
    if not entries:
        print("(keine Log-Einträge)")
        return 0
    print()
    print(f"{'Zeitpunkt':17s}  {'Ereignis':12s}  {'UID':21s}  "
          f"{'Tokens':>6s}  {'Rest':>6s}  {'IP':15s}  {'Module':30s}")
    print("─" * 130)
    for e in entries:
        uid_mask = f"{e['account_uid'][:9]}…{e['account_uid'][-4:]}"
        mods = e.get("modules") or ""
        try:
            parsed = json.loads(mods) if mods else ""
            if isinstance(parsed, list):
                mods = ",".join(parsed)
            elif isinstance(parsed, dict):
                mods = parsed.get("reason") or str(parsed)
        except Exception:
            pass
        print(
            f"{_fmt_date(e['timestamp']):17s}  "
            f"{(e['event_type'] or ''):12s}  "
            f"{uid_mask:21s}  "
            f"{e['tokens_consumed']:>6d}  "
            f"{e['remaining_after']:>6d}  "
            f"{(e['ip'] or '—')[:15]:15s}  "
            f"{str(mods)[:30]:30s}"
        )
        if e.get("fingerprint_match") == 0:
            print(f"  ⚠ Fingerprint-Mismatch bei diesem Ereignis")
    print()
    return 0


def cmd_packages(args) -> int:
    pkgs = licensing.list_packages(only_active=False)
    print()
    print(f"{'Key':12s}  {'Name':30s}  {'Kosten':>7s}  {'aktiv':6s}  Beschreibung")
    print("─" * 100)
    for p in pkgs:
        print(f"{p['key']:12s}  {p['name']:30s}  {p['cost']:>7d}  "
              f"{'ja' if p['is_active'] else 'nein':6s}  {p.get('description') or ''}")
    print()
    return 0


def cmd_backup(args) -> int:
    path = licensing._backup_once()
    if path:
        print(f"✅ Backup: {path}")
        return 0
    print("❌ Backup fehlgeschlagen — siehe Log.")
    return 1


def main(argv=None) -> int:
    parser = argparse.ArgumentParser(
        prog="admin_cli",
        description="Admin-Werkzeug für EEG-Assistent Lizenzierung",
    )
    sub = parser.add_subparsers(dest="cmd", required=True)

    p = sub.add_parser("create-admin", help="Neuen Web-Admin anlegen")
    p.add_argument("--username")

    p = sub.add_parser("create-account", help="Neuen Zugangscode anlegen")
    p.add_argument("--customer", required=True)
    p.add_argument("--email")
    p.add_argument("--device", help="Vom Admin vergebener Gerätename")
    p.add_argument("--tokens", type=int, required=True)
    p.add_argument("--notes")
    p.add_argument("--admin", help="Admin-Username fürs Audit-Log")

    p = sub.add_parser("list", help="Alle Konten listen")
    p.add_argument("--include-disabled", action="store_true")

    p = sub.add_parser("adjust-tokens", help="Tokens erhöhen/verringern")
    p.add_argument("--uid", required=True)
    p.add_argument("--delta", type=int, required=True,
                   help="Positiv = nachladen, negativ = abziehen")
    p.add_argument("--reason", required=True)
    p.add_argument("--admin")

    p = sub.add_parser("disable", help="Konto deaktivieren")
    p.add_argument("--uid", required=True)
    p.add_argument("--admin")

    p = sub.add_parser("enable", help="Deaktiviertes Konto wieder aktivieren")
    p.add_argument("--uid", required=True)
    p.add_argument("--admin")

    p = sub.add_parser("log", help="Nutzungsprotokoll ansehen")
    p.add_argument("--uid", help="Nur Einträge dieser UID (optional)")
    p.add_argument("--limit", type=int, default=50)

    sub.add_parser("packages", help="Paket-Katalog anzeigen")

    sub.add_parser("backup", help="Manuelles Backup erstellen")

    args = parser.parse_args(argv)

    # DB/Schema sicherstellen
    licensing.init_db()

    dispatch = {
        "create-admin":    cmd_create_admin,
        "create-account":  cmd_create_account,
        "list":            cmd_list,
        "adjust-tokens":   cmd_adjust,
        "disable":         lambda a: cmd_set_status(a, "disabled"),
        "enable":          lambda a: cmd_set_status(a, "active"),
        "log":             cmd_log,
        "packages":        cmd_packages,
        "backup":          cmd_backup,
    }
    return dispatch[args.cmd](args)


if __name__ == "__main__":
    sys.exit(main())
