#!/usr/bin/env bash
# ╔══════════════════════════════════════════════════════════════╗
# ║          VayDNS — Auto Install, Configure & Manage          ║
# ║          bash <(curl -fsSL https://vaydns.orx.ma/setup.sh)  ║
# ╚══════════════════════════════════════════════════════════════╝
set -euo pipefail

VAYDNS_DIR="/opt/vaydns"
VAYDNS_REPO="https://github.com/net2share/vaydns"

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

info()  { echo -e "  ${GREEN}[+]${NC} $*"; }
warn()  { echo -e "  ${YELLOW}[!]${NC} $*"; }
error() { echo -e "  ${RED}[✗]${NC} $*"; exit 1; }
step()  { echo -e "\n${CYAN}${BOLD}━━━ $* ━━━${NC}\n"; }

# ═══════════════════════════════════════════════════════════════
# BANNER
# ═══════════════════════════════════════════════════════════════
banner() {
  clear
  echo -e "${CYAN}${BOLD}"
  cat <<'ART'
 __   __           ___  _  _ ___
 \ \ / /__ _ _  _ |   \| \| / __|
  \ V / _ \ || || || |) | .` \__ \
   \_/\___/\_|| ||_|___/|_|\_|___/
             |__/
ART
  echo -e "${NC}${BOLD}  Auto-Install & Configure  ·  vaydns.orx.ma${NC}"
  echo -e "  ${CYAN}──────────────────────────────────────────────${NC}\n"
}

# ═══════════════════════════════════════════════════════════════
# QUESTIONS
# ═══════════════════════════════════════════════════════════════
ask_all() {
  echo -e "  ${BOLD}What are you setting up?${NC}\n"
  echo -e "    ${CYAN}[1]${NC}  Server  — the VPS that receives tunnel traffic"
  echo -e "    ${CYAN}[2]${NC}  Client  — machine that connects through the tunnel\n"
  while true; do
    read -rp "  Choice [1/2]: " _m
    case "$_m" in
      1) MODE="server"; break ;;
      2) MODE="client"; break ;;
      *) warn "Enter 1 or 2" ;;
    esac
  done

  echo ""
  echo -e "  ${BOLD}Tunnel domain${NC}  ${CYAN}(e.g. t.gxofc.com)${NC}\n"
  while true; do
    read -rp "  Domain: " DOMAIN
    DOMAIN="${DOMAIN// /}"
    [[ -n "$DOMAIN" ]] && break
    warn "Domain cannot be empty"
  done
  BASE_DOMAIN=$(echo "$DOMAIN" | cut -d. -f2-)

  if [[ "$MODE" == "server" ]]; then
    echo ""
    echo -e "  ${BOLD}Upstream address${NC}  ${CYAN}(what the server tunnels traffic to)${NC}"
    echo -e "  ${CYAN}  127.0.0.1:8000 = ncat HTTP proxy  |  127.0.0.1:22 = SSH${NC}\n"
    read -rp "  Upstream [127.0.0.1:8000]: " UPSTREAM
    UPSTREAM="${UPSTREAM:-127.0.0.1:8000}"
  else
    echo ""
    echo -e "  ${BOLD}Server public key${NC}  ${CYAN}(hex string from server setup)${NC}\n"
    while true; do
      read -rp "  Pubkey: " PUBKEY
      PUBKEY="${PUBKEY// /}"
      [[ -n "$PUBKEY" ]] && break
      warn "Public key cannot be empty"
    done

    echo ""
    echo -e "  ${BOLD}Transport${NC}"
    echo -e "    ${CYAN}[1]${NC}  DoH — DNS over HTTPS  ${GREEN}(recommended)${NC}"
    echo -e "    ${CYAN}[2]${NC}  DoT — DNS over TLS"
    echo -e "    ${CYAN}[3]${NC}  UDP — Plaintext\n"
    read -rp "  Choice [1]: " _tr
    case "${_tr:-1}" in
      2) TRANSPORT="dot"
         read -rp "  DoT resolver [one.one.one.one:853]: " DOT_ADDR
         DOT_ADDR="${DOT_ADDR:-one.one.one.one:853}" ;;
      3) TRANSPORT="udp"
         read -rp "  UDP resolver [8.8.8.8:53]: " UDP_ADDR
         UDP_ADDR="${UDP_ADDR:-8.8.8.8:53}" ;;
      *) TRANSPORT="doh"
         DOH_URL="https://doh.cloudflare.com/dns-query" ;;
    esac

    read -rp "  Local listen port [7000]: " CLI_PORT
    CLI_PORT="${CLI_PORT:-7000}"
    CLI_LISTEN="127.0.0.1:$CLI_PORT"
  fi

  echo ""
  echo -e "  ${BOLD}Summary:${NC}"
  if [[ "$MODE" == "server" ]]; then
    echo -e "    Mode:      ${GREEN}Server${NC}"
    echo -e "    Domain:    ${CYAN}$DOMAIN${NC}"
    echo -e "    Port:      5300  (redirected from :53)"
    echo -e "    Upstream:  $UPSTREAM"
  else
    echo -e "    Mode:      ${GREEN}Client${NC}"
    echo -e "    Domain:    ${CYAN}$DOMAIN${NC}"
    echo -e "    Transport: $TRANSPORT"
    echo -e "    Listen:    $CLI_LISTEN"
  fi
  echo ""
  read -rp "  Press ENTER to install (Ctrl+C to cancel)... "
}

# ═══════════════════════════════════════════════════════════════
# SYSTEM DEPS
# ═══════════════════════════════════════════════════════════════
install_deps() {
  step "System dependencies"
  if [[ -f /etc/os-release ]]; then
    . /etc/os-release
    OS_ID="${ID:-linux}"; OS_LIKE="${ID_LIKE:-}"
  else
    OS_ID="linux"; OS_LIKE=""
  fi

  PKGS="curl wget git python3 python3-pip"
  if echo "$OS_LIKE $OS_ID" | grep -qiE "debian|ubuntu"; then
    DEBIAN_FRONTEND=noninteractive apt-get update -qq
    DEBIAN_FRONTEND=noninteractive apt-get install -y -qq $PKGS 2>/dev/null || true
  elif echo "$OS_LIKE $OS_ID" | grep -qiE "rhel|centos|fedora|rocky|alma"; then
    yum install -y -q $PKGS 2>/dev/null || dnf install -y -q $PKGS 2>/dev/null || true
  elif echo "$OS_ID" | grep -qi "arch"; then
    pacman -Sy --noconfirm python python-pip curl wget git 2>/dev/null || true
  else
    apt-get install -y -qq $PKGS 2>/dev/null || true
  fi

  pip3 install -q rich 2>/dev/null || true
  info "Done"
}

# ═══════════════════════════════════════════════════════════════
# GO
# ═══════════════════════════════════════════════════════════════
install_go() {
  step "Go language runtime"
  if command -v go &>/dev/null; then
    info "Already installed: $(go version)"; return
  fi
  local arch; arch=$(uname -m)
  case "$arch" in
    x86_64)  GA="amd64" ;;
    aarch64) GA="arm64" ;;
    armv7l)  GA="armv6l" ;;
    *)       error "Unsupported arch: $arch" ;;
  esac
  local VER; VER=$(curl -fsSL "https://go.dev/VERSION?m=text" | head -1)
  info "Downloading $VER..."
  wget -q "https://go.dev/dl/${VER}.linux-${GA}.tar.gz" -O /tmp/go.tar.gz
  rm -rf /usr/local/go
  tar -C /usr/local -xzf /tmp/go.tar.gz
  rm -f /tmp/go.tar.gz
  export PATH="/usr/local/go/bin:$PATH"
  echo 'export PATH="/usr/local/go/bin:$PATH"' > /etc/profile.d/go.sh
  chmod +x /etc/profile.d/go.sh
  info "Installed: $(go version)"
}

# ═══════════════════════════════════════════════════════════════
# BUILD
# ═══════════════════════════════════════════════════════════════
build_vaydns() {
  step "Building VayDNS from source"
  export PATH="/usr/local/go/bin:$PATH"
  mkdir -p "$VAYDNS_DIR"
  if [[ -d "$VAYDNS_DIR/src/.git" ]]; then
    info "Updating source..."; git -C "$VAYDNS_DIR/src" pull -q
  else
    info "Cloning..."; git clone -q "$VAYDNS_REPO" "$VAYDNS_DIR/src"
  fi
  cd "$VAYDNS_DIR/src"
  info "Building vaydns-server..."
  go build -o "$VAYDNS_DIR/vaydns-server" ./vaydns-server
  info "Building vaydns-client..."
  go build -o "$VAYDNS_DIR/vaydns-client" ./vaydns-client
  chmod +x "$VAYDNS_DIR/vaydns-server" "$VAYDNS_DIR/vaydns-client"
  info "Binaries ready → $VAYDNS_DIR"
}

# ═══════════════════════════════════════════════════════════════
# KEYS
# ═══════════════════════════════════════════════════════════════
generate_keys() {
  step "Generating keypair"
  mkdir -p "$VAYDNS_DIR/keys"
  if [[ -f "$VAYDNS_DIR/keys/server.key" ]]; then
    warn "Keys already exist — skipping"; return
  fi
  "$VAYDNS_DIR/vaydns-server" \
    -gen-key \
    -privkey-file "$VAYDNS_DIR/keys/server.key" \
    -pubkey-file  "$VAYDNS_DIR/keys/server.pub"
  chmod 600 "$VAYDNS_DIR/keys/server.key"
  chmod 644 "$VAYDNS_DIR/keys/server.pub"
  info "Keys saved → $VAYDNS_DIR/keys/"
}

# ═══════════════════════════════════════════════════════════════
# CONFIG
# ═══════════════════════════════════════════════════════════════
write_config() {
  step "Writing configuration"
  mkdir -p "$VAYDNS_DIR" "$VAYDNS_DIR/logs" "$VAYDNS_DIR/keys"

  if [[ "$MODE" == "client" ]]; then
    echo "$PUBKEY" > "$VAYDNS_DIR/keys/server.pub"
    chmod 644 "$VAYDNS_DIR/keys/server.pub"
  fi

  cat > "$VAYDNS_DIR/vaydns.conf" <<CONF
[server]
domain = ${DOMAIN}
listen_port = 5300
upstream = ${UPSTREAM:-127.0.0.1:8000}
privkey_file = ${VAYDNS_DIR}/keys/server.key
mtu = 1232
record_type = txt
idle_timeout = 10s
keepalive = 2s
log_level = info

[client]
domain = ${DOMAIN}
listen = ${CLI_LISTEN:-127.0.0.1:7000}
pubkey_file = ${VAYDNS_DIR}/keys/server.pub
transport = ${TRANSPORT:-doh}
doh_url = ${DOH_URL:-https://doh.cloudflare.com/dns-query}
dot_addr = ${DOT_ADDR:-}
udp_addr = ${UDP_ADDR:-8.8.8.8:53}
record_type = txt
idle_timeout = 10s
keepalive = 2s
log_level = info
utls = weighted

[proxy]
mode = none
proxy_type = socks5
CONF
  info "Config → $VAYDNS_DIR/vaydns.conf"
}

# ═══════════════════════════════════════════════════════════════
# FIREWALL
# ═══════════════════════════════════════════════════════════════
apply_firewall() {
  step "Firewall — redirecting UDP :53 → :5300"
  iptables  -I INPUT -p udp --dport 5300 -j ACCEPT                                    2>/dev/null && info "iptables  INPUT 5300"    || warn "iptables skipped (may already exist)"
  iptables  -t nat -I PREROUTING -p udp --dport 53 -j REDIRECT --to-ports 5300        2>/dev/null && info "iptables  NAT  53→5300"  || true
  ip6tables -I INPUT -p udp --dport 5300 -j ACCEPT                                    2>/dev/null && info "ip6tables INPUT 5300"    || true
  ip6tables -t nat -I PREROUTING -p udp --dport 53 -j REDIRECT --to-ports 5300        2>/dev/null && info "ip6tables NAT  53→5300"  || true
}

# ═══════════════════════════════════════════════════════════════
# SYSTEMD — SERVER
# ═══════════════════════════════════════════════════════════════
install_systemd_server() {
  step "Systemd service — vaydns-server"
  cat > /etc/systemd/system/vaydns-server.service <<SVC
[Unit]
Description=VayDNS Server
After=network.target

[Service]
ExecStart=${VAYDNS_DIR}/vaydns-server \\
  -udp :5300 \\
  -domain ${DOMAIN} \\
  -upstream ${UPSTREAM} \\
  -privkey-file ${VAYDNS_DIR}/keys/server.key \\
  -mtu 1232 \\
  -record-type txt \\
  -idle-timeout 10s \\
  -keepalive 2s \\
  -log-level info
Restart=on-failure
RestartSec=5
StandardOutput=append:${VAYDNS_DIR}/logs/server.log
StandardError=append:${VAYDNS_DIR}/logs/server.log

[Install]
WantedBy=multi-user.target
SVC
  systemctl daemon-reload
  systemctl enable vaydns-server
  systemctl start  vaydns-server
  sleep 1
  systemctl is-active --quiet vaydns-server \
    && info "vaydns-server is running" \
    || warn "Service may have failed — run: journalctl -u vaydns-server -n 30"
}

# ═══════════════════════════════════════════════════════════════
# SYSTEMD — CLIENT
# ═══════════════════════════════════════════════════════════════
install_systemd_client() {
  step "Systemd service — vaydns-client"
  local TR_FLAGS=""
  case "$TRANSPORT" in
    doh) TR_FLAGS="-doh ${DOH_URL:-https://doh.cloudflare.com/dns-query} -utls weighted" ;;
    dot) TR_FLAGS="-dot ${DOT_ADDR}" ;;
    udp) TR_FLAGS="-udp ${UDP_ADDR:-8.8.8.8:53}" ;;
  esac
  cat > /etc/systemd/system/vaydns-client.service <<SVC
[Unit]
Description=VayDNS Client
After=network.target

[Service]
ExecStart=${VAYDNS_DIR}/vaydns-client \\
  ${TR_FLAGS} \\
  -domain ${DOMAIN} \\
  -listen ${CLI_LISTEN} \\
  -pubkey-file ${VAYDNS_DIR}/keys/server.pub \\
  -record-type txt \\
  -idle-timeout 10s \\
  -keepalive 2s \\
  -log-level info
Restart=on-failure
RestartSec=5
StandardOutput=append:${VAYDNS_DIR}/logs/client.log
StandardError=append:${VAYDNS_DIR}/logs/client.log

[Install]
WantedBy=multi-user.target
SVC
  systemctl daemon-reload
  systemctl enable vaydns-client
  systemctl start  vaydns-client
  sleep 1
  systemctl is-active --quiet vaydns-client \
    && info "vaydns-client is running" \
    || warn "Service may have failed — run: journalctl -u vaydns-client -n 30"
}

# ═══════════════════════════════════════════════════════════════
# EMBED MENU.PY
# ═══════════════════════════════════════════════════════════════
write_menu() {
  step "Installing management menu"
  mkdir -p "$VAYDNS_DIR"

cat > "$VAYDNS_DIR/menu.py" << 'PYEOF'
#!/usr/bin/env python3
"""VayDNS Terminal Management Menu — vaydns.orx.ma"""
import os, sys, signal, subprocess, time, configparser
from pathlib import Path

try:
    from rich.console import Console
    from rich.table import Table
    from rich.panel import Panel
    from rich.prompt import Prompt, Confirm
    from rich import box
    HAS_RICH = True
except ImportError:
    HAS_RICH = False

VAYDNS_DIR  = Path("/opt/vaydns")
CONFIG_FILE = VAYDNS_DIR / "vaydns.conf"
PID_SERVER  = VAYDNS_DIR / "vaydns-server.pid"
PID_CLIENT  = VAYDNS_DIR / "vaydns-client.pid"
LOG_SERVER  = VAYDNS_DIR / "logs/server.log"
LOG_CLIENT  = VAYDNS_DIR / "logs/client.log"
BIN_SERVER  = VAYDNS_DIR / "vaydns-server"
BIN_CLIENT  = VAYDNS_DIR / "vaydns-client"
KEY_DIR     = VAYDNS_DIR / "keys"
SVC_SERVER  = Path("/etc/systemd/system/vaydns-server.service")
SVC_CLIENT  = Path("/etc/systemd/system/vaydns-client.service")
(VAYDNS_DIR / "logs").mkdir(parents=True, exist_ok=True)
console = Console() if HAS_RICH else None

DEFAULTS = {
    "server": {"domain":"","listen_port":"5300","upstream":"127.0.0.1:8000",
                "privkey_file":str(KEY_DIR/"server.key"),"mtu":"1232",
                "record_type":"txt","idle_timeout":"10s","keepalive":"2s","log_level":"info"},
    "client": {"domain":"","listen":"127.0.0.1:7000","pubkey_file":str(KEY_DIR/"server.pub"),
                "transport":"doh","doh_url":"https://doh.cloudflare.com/dns-query",
                "dot_addr":"","udp_addr":"8.8.8.8:53","record_type":"txt",
                "idle_timeout":"10s","keepalive":"2s","log_level":"info","utls":"weighted"},
    "proxy":  {"mode":"none","proxy_type":"socks5"},
}

def load_cfg():
    c = configparser.ConfigParser()
    for s,v in DEFAULTS.items(): c[s]=v
    if CONFIG_FILE.exists(): c.read(CONFIG_FILE)
    return c

def save_cfg(c):
    with open(CONFIG_FILE,"w") as f: c.write(f)

def read_pid(f):
    try: return int(f.read_text().strip())
    except: return None

def is_running(f):
    p = read_pid(f)
    if p is None: return False
    try: os.kill(p,0); return True
    except ProcessLookupError: return False
    except PermissionError: return True

def stop_proc(pid_f, name):
    p = read_pid(pid_f)
    if p is None: prt_warn(f"{name} not running"); return
    try:
        os.kill(p, signal.SIGTERM); time.sleep(1)
        try: os.kill(p,0); os.kill(p,signal.SIGKILL); prt_warn(f"{name} force-killed")
        except ProcessLookupError: prt_ok(f"{name} stopped")
    except ProcessLookupError: prt_warn(f"{name} was not running")
    finally: pid_f.unlink(missing_ok=True)

def start_proc(cmd, pid_f, log_f, name):
    log_f.parent.mkdir(parents=True, exist_ok=True)
    with open(log_f,"a") as lf:
        proc = subprocess.Popen(cmd, stdout=lf, stderr=lf,
                                stdin=subprocess.DEVNULL, start_new_session=True)
    pid_f.write_text(str(proc.pid)); time.sleep(0.9)
    if is_running(pid_f): prt_ok(f"{name} started (PID {proc.pid})")
    else: prt_err(f"{name} failed — check {log_f}")

def srv_cmd(c):
    s=c["server"]
    return [str(BIN_SERVER),"-udp",f":{s['listen_port']}","-domain",s["domain"],
            "-upstream",s["upstream"],"-privkey-file",s["privkey_file"],
            "-mtu",s["mtu"],"-record-type",s["record_type"],
            "-idle-timeout",s["idle_timeout"],"-keepalive",s["keepalive"],
            "-log-level",s["log_level"]]

def cli_cmd(c):
    cl=c["client"]; cmd=[str(BIN_CLIENT)]
    t=cl["transport"]
    if t=="doh":   cmd+=["-doh",cl["doh_url"]]
    elif t=="dot": cmd+=["-dot",cl["dot_addr"]]
    elif t=="udp": cmd+=["-udp",cl["udp_addr"]]
    cmd+=["-domain",cl["domain"],"-listen",cl["listen"],
          "-pubkey-file",cl["pubkey_file"],"-record-type",cl["record_type"],
          "-idle-timeout",cl["idle_timeout"],"-keepalive",cl["keepalive"],
          "-log-level",cl["log_level"]]
    if t=="doh" and cl.get("utls","weighted")!="none":
        cmd+=["-utls",cl.get("utls","weighted")]
    return cmd

def prt_ok(m):
    if HAS_RICH: console.print(f"  [green][+][/green] {m}")
    else: print(f"  [+] {m}")
def prt_warn(m):
    if HAS_RICH: console.print(f"  [yellow][!][/yellow] {m}")
    else: print(f"  [!] {m}")
def prt_err(m):
    if HAS_RICH: console.print(f"  [red][✗][/red] {m}")
    else: print(f"  [✗] {m}")
def prt_info(m):
    if HAS_RICH: console.print(f"  [cyan]•[/cyan] {m}")
    else: print(f"  • {m}")

def clr(): os.system("clear")
def pause(): input("\n  Press ENTER to continue...")

BANNER=r"""
 __   __           ___  _  _ ___
 \ \ / /__ _ _  _ |   \| \| / __|
  \ V / _ \ || || || |) | .` \__ \
   \_/\___/\_|| ||_|___/|_|\_|___/
             |__/
"""

def print_banner():
    ss = "[green]● RUNNING[/green]" if is_running(PID_SERVER) else "[red]○ STOPPED[/red]"
    cs = "[green]● RUNNING[/green]" if is_running(PID_CLIENT) else "[red]○ STOPPED[/red]"
    if HAS_RICH:
        console.print(f"[cyan]{BANNER}[/cyan]")
        console.print(Panel(f"  Server: {ss}    Client: {cs}",
            title="[bold]VayDNS Management[/bold]",
            subtitle="[dim]vaydns.orx.ma[/dim]",
            border_style="cyan", expand=False))
    else:
        print(BANNER)
        sv="● RUNNING" if is_running(PID_SERVER) else "○ STOPPED"
        cl="● RUNNING" if is_running(PID_CLIENT) else "○ STOPPED"
        print(f"  Server: {sv}    Client: {cl}")
        print("  ─────────────────────────────────")

def menu(title, opts):
    if HAS_RICH:
        t=Table(box=box.SIMPLE,show_header=False,padding=(0,2))
        t.add_column("K",style="bold cyan",width=5)
        t.add_column("A",style="white")
        for k,l in opts: t.add_row(f"[{k}]",l)
        console.print(Panel(t,title=f"[bold]{title}[/bold]",border_style="cyan"))
    else:
        print(f"\n  ── {title} ──")
        for k,l in opts: print(f"    [{k}] {l}")
        print()

def ask(text, default=""):
    if HAS_RICH: return Prompt.ask(f"  [bold cyan]{text}[/bold cyan]",default=default)
    v=input(f"  {text} [{default}]: ").strip(); return v if v else default

def yesno(text, default=False):
    if HAS_RICH: return Confirm.ask(f"  [bold yellow]{text}[/bold yellow]",default=default)
    a=input(f"  {text} [{'Y/n' if default else 'y/N'}]: ").strip().lower()
    return default if not a else a.startswith("y")

def choice(opts):
    valid={o[0].lower() for o in opts}|{"q"}
    while True:
        c=input("  Choice: ").strip().lower()
        if c in valid: return c
        prt_warn("Invalid — try again")

# ── STATUS ────────────────────────────────────────────────────
def do_status():
    clr(); print_banner()
    cfg=load_cfg()
    if HAS_RICH:
        t=Table(title="Processes",box=box.ROUNDED,border_style="cyan")
        t.add_column("Name",style="bold"); t.add_column("Status")
        t.add_column("PID"); t.add_column("Log")
        for n,pf,lf in [("vaydns-server",PID_SERVER,LOG_SERVER),("vaydns-client",PID_CLIENT,LOG_CLIENT)]:
            r=is_running(pf)
            t.add_row(n,"[green]● RUNNING[/green]" if r else "[red]○ STOPPED[/red]",
                      str(read_pid(pf) or "—"),str(lf))
        console.print(t); console.print()
        t2=Table(title="Configuration",box=box.ROUNDED,border_style="cyan")
        t2.add_column("Key",style="cyan"); t2.add_column("Value")
        s,c=cfg["server"],cfg["client"]
        for k,v in [("Server domain",s.get("domain","—")),
                    ("Server port",s.get("listen_port","5300")),
                    ("Server upstream",s.get("upstream","—")),
                    ("Client domain",c.get("domain","—")),
                    ("Client listen",c.get("listen","127.0.0.1:7000")),
                    ("Client transport",c.get("transport","doh"))]:
            t2.add_row(k,v)
        console.print(t2)
    else:
        for n,pf,lf in [("vaydns-server",PID_SERVER,LOG_SERVER),("vaydns-client",PID_CLIENT,LOG_CLIENT)]:
            r=is_running(pf); p=read_pid(pf) or "—"
            print(f"  {n}: {'RUNNING' if r else 'STOPPED'}  PID={p}  Log={lf}")
        s,c=cfg["server"],cfg["client"]
        print(f"\n  Server domain: {s.get('domain','—')}  port: {s.get('listen_port','5300')}")
        print(f"  Client domain: {c.get('domain','—')}  listen: {c.get('listen','—')}")
    pause()

# ── SERVER MENU ───────────────────────────────────────────────
def do_server():
    cfg=load_cfg()
    while True:
        clr(); print_banner()
        opts=[("s","Start server"),("k","Stop server"),("r","Restart server"),
              ("c","Configure server"),("g","Generate new keypair"),
              ("l","View server logs"),("i","Install systemd service"),
              ("u","Uninstall systemd service"),("b","Back")]
        menu("Server Management", opts); ch=choice(opts)

        if ch=="s":
            cfg=load_cfg()
            if not cfg["server"]["domain"]: prt_warn("Configure domain first"); pause(); continue
            if is_running(PID_SERVER): prt_warn("Already running")
            else:
                cmd=srv_cmd(cfg); prt_info(f"$ {' '.join(cmd)}")
                start_proc(cmd,PID_SERVER,LOG_SERVER,"vaydns-server")
            pause()
        elif ch=="k": stop_proc(PID_SERVER,"vaydns-server"); pause()
        elif ch=="r":
            stop_proc(PID_SERVER,"vaydns-server"); time.sleep(1)
            cfg=load_cfg()
            if cfg["server"]["domain"]: start_proc(srv_cmd(cfg),PID_SERVER,LOG_SERVER,"vaydns-server")
            pause()
        elif ch=="c": cfg=do_cfg_server(cfg)
        elif ch=="g": do_genkey(); pause()
        elif ch=="l": do_logs(LOG_SERVER,"Server Logs")
        elif ch=="i": do_svc_server(cfg); pause()
        elif ch=="u": do_svc_rm("vaydns-server",SVC_SERVER); pause()
        elif ch in("b","q"): break

# ── CLIENT MENU ───────────────────────────────────────────────
def do_client():
    cfg=load_cfg()
    while True:
        clr(); print_banner()
        opts=[("s","Start client"),("k","Stop client"),("r","Restart client"),
              ("c","Configure client"),("l","View client logs"),
              ("t","Test tunnel connection"),("i","Install systemd service"),
              ("u","Uninstall systemd service"),("b","Back")]
        menu("Client Management", opts); ch=choice(opts)

        if ch=="s":
            cfg=load_cfg()
            if not cfg["client"]["domain"]: prt_warn("Configure domain first"); pause(); continue
            if is_running(PID_CLIENT): prt_warn("Already running")
            else:
                cmd=cli_cmd(cfg); prt_info(f"$ {' '.join(cmd)}")
                start_proc(cmd,PID_CLIENT,LOG_CLIENT,"vaydns-client")
            pause()
        elif ch=="k": stop_proc(PID_CLIENT,"vaydns-client"); pause()
        elif ch=="r":
            stop_proc(PID_CLIENT,"vaydns-client"); time.sleep(1)
            cfg=load_cfg()
            if cfg["client"]["domain"]: start_proc(cli_cmd(cfg),PID_CLIENT,LOG_CLIENT,"vaydns-client")
            pause()
        elif ch=="c": cfg=do_cfg_client(cfg)
        elif ch=="l": do_logs(LOG_CLIENT,"Client Logs")
        elif ch=="t": do_test(cfg); pause()
        elif ch=="i": do_svc_client(cfg); pause()
        elif ch=="u": do_svc_rm("vaydns-client",SVC_CLIENT); pause()
        elif ch in("b","q"): break

# ── TOOLS MENU ────────────────────────────────────────────────
def do_tools():
    while True:
        clr(); print_banner()
        opts=[("k","Key manager"),("p","Proxy wizard"),("f","Firewall helper"),
              ("z","DNS zone guide"),("u","Update VayDNS"),("b","Back")]
        menu("Tools & Utilities", opts); ch=choice(opts)
        if ch=="k": do_keys()
        elif ch=="p": do_proxy(); pause()
        elif ch=="f": do_fw(); pause()
        elif ch=="z": do_dns(); pause()
        elif ch=="u": do_update(); pause()
        elif ch in("b","q"): break

# ── CONFIGURE ────────────────────────────────────────────────
def do_cfg_server(cfg):
    clr()
    if HAS_RICH: console.print(Panel("[bold]Configure Server[/bold]",border_style="cyan"))
    else: print("\n  ── Configure Server ──")
    s=cfg["server"]
    s["domain"]       = ask("Tunnel domain",s["domain"])
    s["listen_port"]  = ask("UDP listen port",s["listen_port"])
    s["upstream"]     = ask("Upstream TCP (proxy/SSH/etc)",s["upstream"])
    s["privkey_file"] = ask("Private key file",s["privkey_file"])
    s["mtu"]          = ask("MTU",s["mtu"])
    s["record_type"]  = ask("Record type [txt/null/cname/a/aaaa/mx/ns/srv/caa]",s["record_type"])
    s["idle_timeout"] = ask("Idle timeout",s["idle_timeout"])
    s["keepalive"]    = ask("Keepalive (< idle-timeout)",s["keepalive"])
    s["log_level"]    = ask("Log level [debug/info/warning/error]",s["log_level"])
    save_cfg(cfg); prt_ok("Server config saved"); pause(); return load_cfg()

def do_cfg_client(cfg):
    clr()
    if HAS_RICH: console.print(Panel("[bold]Configure Client[/bold]",border_style="cyan"))
    else: print("\n  ── Configure Client ──")
    c=cfg["client"]
    c["domain"]      = ask("Tunnel domain (must match server)",c["domain"])
    c["listen"]      = ask("Local listen address",c["listen"])
    c["pubkey_file"] = ask("Server public key file",c["pubkey_file"])
    prt_info("Transport: [1] DoH  [2] DoT  [3] UDP")
    tr=input("  Select [1]: ").strip() or "1"
    if tr=="1":
        c["transport"]="doh"
        c["doh_url"]=ask("DoH resolver URL",c.get("doh_url","https://doh.cloudflare.com/dns-query"))
        c["utls"]=ask("uTLS [weighted/Firefox/Chrome/random/none]",c.get("utls","weighted"))
    elif tr=="2":
        c["transport"]="dot"
        c["dot_addr"]=ask("DoT resolver host:853",c.get("dot_addr",""))
    else:
        c["transport"]="udp"
        c["udp_addr"]=ask("UDP resolver host:53",c.get("udp_addr","8.8.8.8:53"))
    c["record_type"] = ask("Record type",c["record_type"])
    c["idle_timeout"]= ask("Idle timeout (match server)",c["idle_timeout"])
    c["keepalive"]   = ask("Keepalive (match server)",c["keepalive"])
    c["log_level"]   = ask("Log level",c["log_level"])
    save_cfg(cfg); prt_ok("Client config saved"); pause(); return load_cfg()

# ── KEY MANAGER ───────────────────────────────────────────────
def do_genkey():
    KEY_DIR.mkdir(parents=True, exist_ok=True)
    if not BIN_SERVER.exists(): prt_err(f"Binary not found: {BIN_SERVER}"); return
    r=subprocess.run([str(BIN_SERVER),"-gen-key",
                      "-privkey-file",str(KEY_DIR/"server.key"),
                      "-pubkey-file",str(KEY_DIR/"server.pub")],
                     capture_output=True, text=True)
    if r.returncode==0:
        prt_ok(f"Keys saved → {KEY_DIR}/")
        pub=(KEY_DIR/"server.pub").read_text().strip()
        if HAS_RICH: console.print(f"\n  [bold yellow]Public key:[/bold yellow] [cyan]{pub}[/cyan]")
        else: print(f"\n  Public key: {pub}")
    else: prt_err(f"Failed: {r.stderr}")

def do_keys():
    while True:
        clr()
        opts=[("g","Generate new keypair"),("s","Show public key"),
              ("p","Show private key (⚠ sensitive)"),("b","Back")]
        menu("Key Manager",opts); ch=choice(opts)
        if ch=="g":
            if (KEY_DIR/"server.key").exists():
                if not yesno("Overwrite existing keys?",False): continue
            do_genkey(); pause()
        elif ch=="s":
            pub=KEY_DIR/"server.pub"
            if pub.exists():
                if HAS_RICH: console.print(f"\n  [cyan]{pub.read_text().strip()}[/cyan]")
                else: print(f"\n  {pub.read_text().strip()}")
            else: prt_warn("No key found. Generate first.")
            pause()
        elif ch=="p":
            priv=KEY_DIR/"server.key"
            if priv.exists() and yesno("⚠  Show private key?",False):
                if HAS_RICH: console.print(f"\n  [red]{priv.read_text().strip()}[/red]")
                else: print(f"\n  {priv.read_text().strip()}")
            pause()
        elif ch in("b","q"): break

# ── LOGS ──────────────────────────────────────────────────────
def do_logs(log_f, title):
    clr()
    if HAS_RICH: console.print(Panel(f"[bold]{title}[/bold]  [dim]{log_f}[/dim]",border_style="cyan"))
    else: print(f"\n  ── {title} ({log_f})")
    if not log_f.exists(): prt_warn("No log file yet"); pause(); return
    r=subprocess.run(["tail","-n","80",str(log_f)],capture_output=True,text=True)
    if HAS_RICH:
        from rich.syntax import Syntax
        console.print(Syntax(r.stdout,"text",theme="monokai",line_numbers=True,word_wrap=True))
    else: print(r.stdout)
    print("  [f] Follow live   [ENTER] Back")
    if input("  ").strip().lower()=="f":
        try:
            p=subprocess.Popen(["tail","-f",str(log_f)])
            print("  Ctrl+C to stop"); p.wait()
        except KeyboardInterrupt: p.terminate()

# ── TEST ──────────────────────────────────────────────────────
def do_test(cfg):
    clr(); listen=cfg["client"].get("listen","127.0.0.1:7000")
    host,port=listen.rsplit(":",1)
    prt_info(f"Testing TCP {listen} ...")
    r=subprocess.run(["bash","-c",
                      f"echo|timeout 3 nc -z {host} {port} && echo OK || echo FAIL"],
                     capture_output=True,text=True)
    if "OK" in r.stdout: prt_ok(f"{listen} is OPEN — tunnel working!")
    else: prt_warn(f"Cannot reach {listen} — client may be down")
    prt_info("Testing HTTP proxy exit IP...")
    try:
        r2=subprocess.run(["curl","-s","--max-time","5",
                           "--proxy",f"http://{listen}/","https://wtfismyip.com/text"],
                          capture_output=True,text=True)
        if r2.returncode==0 and r2.stdout.strip():
            prt_ok(f"Exit IP via tunnel: {r2.stdout.strip()}")
        else: prt_info("HTTP proxy test inconclusive (mode may not be http-proxy)")
    except: pass

# ── PROXY WIZARD ──────────────────────────────────────────────
def do_proxy():
    clr(); cfg=load_cfg()
    opts=[("1","HTTP proxy via ncat (easiest)"),
          ("2","SOCKS5 via SSH — server-side"),
          ("3","SOCKS5 via SSH — client-side (private)"),
          ("4","Tor bridge")]
    menu("Proxy Wizard",opts)
    ch=input("  Choice [1]: ").strip() or "1"
    d=cfg["server"].get("domain","t.example.com")
    sp=cfg["server"].get("listen_port","5300")
    pk=cfg["server"].get("privkey_file","/opt/vaydns/keys/server.key")
    cl=cfg["client"].get("listen","127.0.0.1:7000")
    du=cfg["client"].get("doh_url","https://doh.cloudflare.com/dns-query")
    pp=cfg["client"].get("pubkey_file","/opt/vaydns/keys/server.pub")
    if ch=="1":
        print(f"\n  Server:\n    ncat -l -k --proxy-type http 127.0.0.1 8000")
        print(f"    {BIN_SERVER} -udp :{sp} -privkey-file {pk} -domain {d} -upstream 127.0.0.1:8000")
        print(f"\n  Client:\n    {BIN_CLIENT} -doh {du} -pubkey-file {pp} -domain {d} -listen {cl}")
        print(f"    curl --proxy http://{cl}/ https://wtfismyip.com/text")
    elif ch=="2":
        print(f"\n  Server:\n    ssh -N -D 127.0.0.1:8000 -o NoHostAuthenticationForLocalhost=yes 127.0.0.1")
        print(f"    {BIN_SERVER} -udp :{sp} -privkey-file {pk} -domain {d} -upstream 127.0.0.1:8000")
        print(f"\n  Client:\n    {BIN_CLIENT} -doh {du} -pubkey-file {pp} -domain {d} -listen {cl}")
        print(f"    curl --proxy socks5h://{cl}/ https://wtfismyip.com/text")
    elif ch=="3":
        print(f"\n  Server:\n    {BIN_SERVER} -udp :{sp} -privkey-file {pk} -domain {d} -upstream 127.0.0.1:22")
        print(f"\n  Client:\n    {BIN_CLIENT} -doh {du} -pubkey-file {pp} -domain {d} -listen 127.0.0.1:8000")
        print(f"    ssh -N -D 127.0.0.1:7000 -o HostKeyAlias=tunnel-server -p 8000 127.0.0.1")
        print(f"    curl --proxy socks5h://127.0.0.1:7000/ https://wtfismyip.com/text")
    elif ch=="4":
        print(f"\n  Server:\n    {BIN_SERVER} -udp :{sp} -privkey-file {pk} -domain {d} -upstream 127.0.0.1:9001")
        print(f"\n  torrc:\n    Bridge 127.0.0.1:{cl.split(':')[-1]} <FINGERPRINT>")

# ── FIREWALL HELPER ───────────────────────────────────────────
def do_fw():
    clr(); cfg=load_cfg(); port=cfg["server"].get("listen_port","5300")
    if HAS_RICH: console.print(Panel("[bold]Firewall — iptables[/bold]",border_style="cyan"))
    cmds=[f"sudo iptables  -I INPUT -p udp --dport {port} -j ACCEPT",
          f"sudo iptables  -t nat -I PREROUTING -i eth0 -p udp --dport 53 -j REDIRECT --to-ports {port}",
          f"sudo ip6tables -I INPUT -p udp --dport {port} -j ACCEPT",
          f"sudo ip6tables -t nat -I PREROUTING -i eth0 -p udp --dport 53 -j REDIRECT --to-ports {port}"]
    for c in cmds: print(f"    {c}")
    if yesno("\n  Apply these rules now?",False):
        for c in cmds:
            r=subprocess.run(c,shell=True,capture_output=True)
            if r.returncode==0: prt_ok(c)
            else: prt_err(f"Failed: {c}")

# ── DNS ZONE GUIDE ────────────────────────────────────────────
def do_dns():
    clr(); cfg=load_cfg()
    d=cfg["server"].get("domain") or "t.example.com"
    base=d.split(".",1)[1] if "." in d else "example.com"
    tns=f"tns.{base}"
    if HAS_RICH:
        console.print(Panel("[bold]DNS Zone Setup[/bold]",border_style="cyan"))
        t=Table(box=box.ROUNDED)
        t.add_column("Type"); t.add_column("Name"); t.add_column("Value")
        t.add_row("A",tns,"YOUR_SERVER_IP")
        t.add_row("AAAA",tns,"YOUR_SERVER_IPv6  (optional)")
        t.add_row("NS",d,tns)
        console.print(t)
    else:
        print(f"\n  A     {tns}  →  YOUR_SERVER_IP")
        print(f"  AAAA  {tns}  →  YOUR_SERVER_IPv6  (optional)")
        print(f"  NS    {d}  →  {tns}")
    prt_info(f"Queries for *.{d} will route to your tunnel server")

# ── SYSTEMD HELPERS ───────────────────────────────────────────
def do_svc_server(cfg):
    cmd=" \\\n  ".join(srv_cmd(cfg))
    s=f"""[Unit]
Description=VayDNS Server
After=network.target

[Service]
ExecStart={cmd}
Restart=on-failure
RestartSec=5
StandardOutput=append:{LOG_SERVER}
StandardError=append:{LOG_SERVER}

[Install]
WantedBy=multi-user.target
"""
    try:
        SVC_SERVER.write_text(s)
        subprocess.run(["systemctl","daemon-reload"],check=True)
        subprocess.run(["systemctl","enable","vaydns-server"],check=True)
        prt_ok("vaydns-server service installed")
        prt_info("Start: systemctl start vaydns-server")
    except Exception as e: prt_err(str(e))

def do_svc_client(cfg):
    cmd=" \\\n  ".join(cli_cmd(cfg))
    s=f"""[Unit]
Description=VayDNS Client
After=network.target

[Service]
ExecStart={cmd}
Restart=on-failure
RestartSec=5
StandardOutput=append:{LOG_CLIENT}
StandardError=append:{LOG_CLIENT}

[Install]
WantedBy=multi-user.target
"""
    try:
        SVC_CLIENT.write_text(s)
        subprocess.run(["systemctl","daemon-reload"],check=True)
        subprocess.run(["systemctl","enable","vaydns-client"],check=True)
        prt_ok("vaydns-client service installed")
        prt_info("Start: systemctl start vaydns-client")
    except Exception as e: prt_err(str(e))

def do_svc_rm(name, svc_f):
    try:
        subprocess.run(["systemctl","stop",name],capture_output=True)
        subprocess.run(["systemctl","disable",name],capture_output=True)
        svc_f.unlink(missing_ok=True)
        subprocess.run(["systemctl","daemon-reload"],check=True)
        prt_ok(f"{name} service removed")
    except Exception as e: prt_err(str(e))

# ── UPDATE ────────────────────────────────────────────────────
def do_update():
    clr(); src=VAYDNS_DIR/"src"
    if not src.exists(): prt_err("Source missing. Run setup.sh first."); return
    try:
        was_s=is_running(PID_SERVER); was_c=is_running(PID_CLIENT)
        stop_proc(PID_SERVER,"vaydns-server"); stop_proc(PID_CLIENT,"vaydns-client")
        subprocess.run(["git","-C",str(src),"pull"],check=True)
        subprocess.run(["go","build","-o",str(BIN_SERVER),"./vaydns-server"],cwd=str(src),check=True)
        subprocess.run(["go","build","-o",str(BIN_CLIENT),"./vaydns-client"],cwd=str(src),check=True)
        prt_ok("Binaries updated!")
        cfg=load_cfg()
        if was_s: start_proc(srv_cmd(cfg),PID_SERVER,LOG_SERVER,"vaydns-server")
        if was_c: start_proc(cli_cmd(cfg),PID_CLIENT,LOG_CLIENT,"vaydns-client")
    except subprocess.CalledProcessError as e: prt_err(f"Update failed: {e}")

# ── MAIN ──────────────────────────────────────────────────────
def main_menu():
    while True:
        clr(); print_banner()
        opts=[("1","Status overview"),("2","Server management"),
              ("3","Client management"),("4","Tools & Utilities"),("q","Quit")]
        menu("Main Menu",opts); ch=choice(opts)
        if ch=="1": do_status()
        elif ch=="2": do_server()
        elif ch=="3": do_client()
        elif ch=="4": do_tools()
        elif ch=="q":
            if HAS_RICH: console.print("\n  [cyan]Goodbye![/cyan]\n")
            else: print("\n  Goodbye!\n")
            sys.exit(0)

def cli_flags():
    a=sys.argv[1:]; cfg=load_cfg()
    if "--server"      in a:
        if is_running(PID_SERVER): prt_warn("Already running")
        else: start_proc(srv_cmd(cfg),PID_SERVER,LOG_SERVER,"vaydns-server")
    elif "--client"    in a:
        if is_running(PID_CLIENT): prt_warn("Already running")
        else: start_proc(cli_cmd(cfg),PID_CLIENT,LOG_CLIENT,"vaydns-client")
    elif "--stop-server" in a: stop_proc(PID_SERVER,"vaydns-server")
    elif "--stop-client" in a: stop_proc(PID_CLIENT,"vaydns-client")
    elif "--status"    in a:
        for n,pf in [("vaydns-server",PID_SERVER),("vaydns-client",PID_CLIENT)]:
            print(f"  {n}: {'RUNNING' if is_running(pf) else 'STOPPED'}  PID={read_pid(pf) or '—'}")
    elif "--gen-key"   in a: do_genkey()
    else: main_menu()

if __name__=="__main__":
    cli_flags()
PYEOF

  chmod +x "$VAYDNS_DIR/menu.py"
  pip3 install -q rich 2>/dev/null || true

  cat > /usr/local/bin/vaydns << 'WRAPPER'
#!/usr/bin/env bash
exec python3 /opt/vaydns/menu.py "$@"
WRAPPER
  chmod +x /usr/local/bin/vaydns
  info "'vaydns' command ready"
}

# ═══════════════════════════════════════════════════════════════
# SUMMARIES
# ═══════════════════════════════════════════════════════════════
summary_server() {
  local PUB; PUB=$(cat "$VAYDNS_DIR/keys/server.pub" 2>/dev/null || echo "N/A")
  local IP;  IP=$(curl -fsSL https://api.ipify.org 2>/dev/null \
                  || curl -fsSL https://icanhazip.com 2>/dev/null \
                  || hostname -I | awk '{print $1}')
  echo ""
  echo -e "${CYAN}${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
  echo -e "${GREEN}${BOLD}  ✔  VayDNS Server installed and running!${NC}"
  echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
  echo ""
  echo -e "  ${BOLD}Domain:${NC}   ${CYAN}$DOMAIN${NC}"
  echo -e "  ${BOLD}Port:${NC}     5300  (also :53 via iptables)"
  echo -e "  ${BOLD}Upstream:${NC} $UPSTREAM"
  echo ""
  echo -e "  ${BOLD}▶ Public key — copy this to your client:${NC}"
  echo -e "  ${YELLOW}${PUB}${NC}"
  echo ""
  echo -e "  ${BOLD}▶ Add these DNS records at your registrar:${NC}"
  echo ""
  printf "  %-6s  %-28s  %s\n" "TYPE" "NAME" "VALUE"
  echo   "  ─────────────────────────────────────────────────────"
  printf "  %-6s  %-28s  %s\n" "A"  "tns.$BASE_DOMAIN"  "$IP"
  printf "  %-6s  %-28s  %s\n" "NS" "$DOMAIN"            "tns.$BASE_DOMAIN"
  echo ""
  echo -e "  ${BOLD}▶ Commands:${NC}"
  echo -e "    ${CYAN}vaydns${NC}                          open menu"
  echo -e "    ${CYAN}vaydns --status${NC}                 quick status"
  echo -e "    ${CYAN}systemctl status vaydns-server${NC}"
  echo -e "    ${CYAN}tail -f $VAYDNS_DIR/logs/server.log${NC}"
  echo ""
  echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
  echo ""
}

summary_client() {
  echo ""
  echo -e "${CYAN}${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
  echo -e "${GREEN}${BOLD}  ✔  VayDNS Client installed and running!${NC}"
  echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
  echo ""
  echo -e "  ${BOLD}Domain:${NC}     ${CYAN}$DOMAIN${NC}"
  echo -e "  ${BOLD}Transport:${NC}  $TRANSPORT"
  echo -e "  ${BOLD}Listen:${NC}     ${CYAN}$CLI_LISTEN${NC}  ← your local tunnel port"
  echo ""
  echo -e "  ${BOLD}▶ Test the tunnel:${NC}"
  echo -e "    ${CYAN}nc -z 127.0.0.1 $CLI_PORT && echo 'Tunnel OK'${NC}"
  echo -e "    ${CYAN}curl --proxy http://$CLI_LISTEN/ https://wtfismyip.com/text${NC}"
  echo ""
  echo -e "  ${BOLD}▶ Browser proxy:${NC}  HTTP / SOCKS5  →  ${CYAN}127.0.0.1:$CLI_PORT${NC}"
  echo ""
  echo -e "  ${BOLD}▶ Commands:${NC}"
  echo -e "    ${CYAN}vaydns${NC}                          open menu"
  echo -e "    ${CYAN}vaydns --status${NC}                 quick status"
  echo -e "    ${CYAN}systemctl status vaydns-client${NC}"
  echo -e "    ${CYAN}tail -f $VAYDNS_DIR/logs/client.log${NC}"
  echo ""
  echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
  echo ""
}

# ═══════════════════════════════════════════════════════════════
# MAIN
# ═══════════════════════════════════════════════════════════════
main() {
  banner
  [[ $EUID -ne 0 ]] && error "Run as root:\n  sudo bash <(curl -fsSL https://vaydns.orx.ma/setup.sh)"

  # Declare globals with safe defaults
  MODE="server"; DOMAIN=""; BASE_DOMAIN=""
  UPSTREAM="127.0.0.1:8000"; PUBKEY=""
  TRANSPORT="doh"; DOH_URL="https://doh.cloudflare.com/dns-query"
  DOT_ADDR=""; UDP_ADDR="8.8.8.8:53"
  CLI_PORT="7000"; CLI_LISTEN="127.0.0.1:7000"

  ask_all        # ← only user interaction happens here

  install_deps
  install_go
  build_vaydns

  if [[ "$MODE" == "server" ]]; then
    generate_keys
    write_config
    apply_firewall
    install_systemd_server
    write_menu
    summary_server
  else
    write_config
    install_systemd_client
    write_menu
    summary_client
  fi

  echo -e "  ${BOLD}Opening management menu...${NC}"
  sleep 2
  exec python3 "$VAYDNS_DIR/menu.py"
}

main "$@"
