#!/bin/bash
# BDUSP DDoS Guard CLI v2

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

BASE="/var/lib/ddos-guard"
BLOCKED_FILE="$BASE/blocked_ips.json"
QUARANTINE_FILE="$BASE/quarantine.json"
WHITELIST_FILE="$BASE/whitelist.json"
BLOCKLIST_FILE="$BASE/blocklist.json"
CONFIG_FILE="$BASE/config.json"
LOG_FILE="/var/log/ddos-guard.log"

header() {
    echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
    echo -e "${CYAN}  🛡️  BDUSP DDoS Guard v2${NC}"
    echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
}

py() { python3 -c "$1"; }

cfg_get() {
    py "
import json
try:
    d=json.load(open('$CONFIG_FILE'))
except:
    d={}
defaults={'window_seconds':30,'block_threshold':100,'perm_threshold':500,
'domain_threshold':300,'quarantine_release_at':500,'quarantine_cooldown':600,
'check_interval':5,'server_wide_enabled':False,'server_wide_threshold':30000}
defaults.update(d)
print(defaults.get('$1',''))
"
}

cfg_set() {
    py "
import json,os
os.makedirs('$BASE',exist_ok=True)
try:
    d=json.load(open('$CONFIG_FILE'))
except:
    d={}
v='$2'
try: v=int(v)
except:
    try: v=float(v)
    except:
        if v.lower()=='true': v=True
        elif v.lower()=='false': v=False
d['$1']=v
json.dump(d,open('$CONFIG_FILE','w'),indent=2)
print('  Set $1 =',v)
"
}

# ── status ────────────────────────────────────────────────────────────────────
cmd_status() {
    header; echo ""
    if systemctl is-active --quiet ddos-guard; then
        echo -e "  Service:    ${GREEN}● Running${NC}"
    else
        echo -e "  Service:    ${RED}● Stopped${NC}"
    fi
    total=$(py "import json
try: d=json.load(open('$BLOCKED_FILE')); print(len(d))
except: print(0)")
    perm=$(py "import json
try: d=json.load(open('$BLOCKED_FILE')); print(sum(1 for v in d.values() if v.get('permanent')))
except: print(0)")
    qcount=$(py "import json
try: d=json.load(open('$QUARANTINE_FILE')); print(len(d))
except: print(0)")
    echo -e "  Blocked:    ${RED}${total} IP(s)${NC} (${perm} permanent)"
    echo -e "  Quarantine: ${YELLOW}${qcount} domain(s)${NC}"
    echo ""
    echo -e "  ${BOLD}Active Config:${NC}"
    echo -e "  Window          : $(cfg_get window_seconds)s"
    echo -e "  Block threshold : $(cfg_get block_threshold) req/window"
    echo -e "  Perm threshold  : $(cfg_get perm_threshold) req/window"
    echo -e "  Domain threshold: $(cfg_get domain_threshold) req/window → quarantine"
    echo -e "  Quarantine off  : < $(cfg_get quarantine_release_at) req + $(cfg_get quarantine_cooldown)s cooldown"
    sw=$(cfg_get server_wide_enabled)
    swt=$(cfg_get server_wide_threshold)
    if [ "$sw" = "True" ]; then
        echo -e "  Server-wide     : ${GREEN}ON${NC} (threshold: $swt req/window)"
    else
        echo -e "  Server-wide     : ${RED}OFF${NC} (threshold: $swt req/window)"
    fi
    echo ""
}

# ── config ────────────────────────────────────────────────────────────────────
cmd_config() {
    local key="$1" val="$2"
    if [ -z "$key" ]; then
        header
        echo ""
        echo -e "  ${BOLD}Editable config keys:${NC}"
        echo ""
        echo -e "  ${CYAN}vg config <key> <value>${NC}"
        echo ""
        echo -e "  ${GREEN}window_seconds${NC}          30       Monitoring window (seconds)"
        echo -e "  ${GREEN}block_threshold${NC}         100      Req/window → 7-day block"
        echo -e "  ${GREEN}perm_threshold${NC}          500      Req/window → permanent block"
        echo -e "  ${GREEN}domain_threshold${NC}        300      Req/window to domain → quarantine"
        echo -e "  ${GREEN}quarantine_release_at${NC}   500      Traffic below this → quarantine off"
        echo -e "  ${GREEN}quarantine_cooldown${NC}     600      Seconds to wait before releasing"
        echo -e "  ${GREEN}check_interval${NC}          5        Log check interval (seconds)"
        echo -e "  ${GREEN}server_wide_enabled${NC}     false    All-domain quarantine on/off"
        echo -e "  ${GREEN}server_wide_threshold${NC}   30000    Total req/window → all quarantine"
        echo ""
        echo -e "  ${YELLOW}Examples:${NC}"
        echo -e "  vg config block_threshold 200"
        echo -e "  vg config server_wide_enabled true"
        echo -e "  vg config server_wide_threshold 50000"
        echo ""
        return
    fi
    if [ -z "$val" ]; then
        echo -e "${RED}Usage: vg config <key> <value>${NC}"; exit 1
    fi
    cfg_set "$key" "$val"
    systemctl restart ddos-guard
    echo -e "${GREEN}✅ Config updated and service restarted.${NC}"
}

# ── blocked ───────────────────────────────────────────────────────────────────
cmd_blocked() {
    header
    echo -e "\n  ${BOLD}Auto-Blocked IPs:${NC}\n"
    py "
import json,time
try: data=json.load(open('$BLOCKED_FILE'))
except: data={}
if not data: print('  No blocked IPs.'); exit()
print(f\"  {'IP':<20} {'Type':<12} {'Blocked At':<22} {'Expires'}\")
print(f\"  {'─'*20} {'─'*12} {'─'*22} {'─'*20}\")
for ip,i in data.items():
    t=i.get('permanent',False)
    bt=time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(i.get('time',0)))
    ex='Never' if t else time.strftime('%Y-%m-%d %H:%M',time.localtime(i.get('time',0)+i.get('duration',0)))
    print(f\"  {ip:<20} {'PERMANENT' if t else '7 Days':<12} {bt:<22} {ex}\")
print()
"
}

# ── whitelist ─────────────────────────────────────────────────────────────────
cmd_whitelist_add() {
    [ -z "$1" ] && echo -e "${RED}Usage: vg whitelist-add <ip> [note]${NC}" && exit 1
    py "
import json,time,os
os.makedirs('$BASE',exist_ok=True)
try: d=json.load(open('$WHITELIST_FILE'))
except: d={}
d['$1']={'added':time.time(),'note':'${2:-manual}'}
json.dump(d,open('$WHITELIST_FILE','w'),indent=2)
"
    echo -e "${GREEN}✅ $1 added to whitelist.${NC}"
    echo -e "${YELLOW}   (Flood still triggers quarantine, but IP won't be blocked)${NC}"
}

cmd_whitelist_remove() {
    [ -z "$1" ] && echo -e "${RED}Usage: vg whitelist-remove <ip>${NC}" && exit 1
    py "
import json
try: d=json.load(open('$WHITELIST_FILE')); d.pop('$1',None); json.dump(d,open('$WHITELIST_FILE','w'),indent=2); print('  Removed.')
except: print('  Not found.')
"
    echo -e "${GREEN}✅ Done.${NC}"
}

cmd_whitelist() {
    header
    echo -e "\n  ${BOLD}Whitelist:${NC}"
    echo -e "  ${YELLOW}(These IPs won't be blocked but quarantine still activates)${NC}\n"
    py "
import json,time
defaults={'127.0.0.1':{'added':0,'note':'system'},'::1':{'added':0,'note':'system'}}
try: u=json.load(open('$WHITELIST_FILE')); defaults.update(u)
except: pass
print(f\"  {'IP':<22} {'Added':<22} {'Note'}\")
print(f\"  {'─'*22} {'─'*22} {'─'*20}\")
for ip,i in defaults.items():
    added=time.strftime('%Y-%m-%d %H:%M',time.localtime(i.get('added',0))) if i.get('added') else 'system'
    print(f\"  {ip:<22} {added:<22} {i.get('note','')}\")
print()
"
}

# ── blocklist ─────────────────────────────────────────────────────────────────
cmd_blocklist_add() {
    [ -z "$1" ] && echo -e "${RED}Usage: vg blocklist-add <ip> [note]${NC}" && exit 1
    iptables -I INPUT -s "$1" -j DROP 2>/dev/null
    iptables -I OUTPUT -d "$1" -j DROP 2>/dev/null
    py "
import json,time,os
os.makedirs('$BASE',exist_ok=True)
try: d=json.load(open('$BLOCKLIST_FILE'))
except: d={}
d['$1']={'added':time.time(),'note':'${2:-manual}','permanent':True}
json.dump(d,open('$BLOCKLIST_FILE','w'),indent=2)
"
    echo -e "${GREEN}✅ $1 permanently blocked and added to blocklist.${NC}"
}

cmd_blocklist_remove() {
    [ -z "$1" ] && echo -e "${RED}Usage: vg blocklist-remove <ip>${NC}" && exit 1
    iptables -D INPUT -s "$1" -j DROP 2>/dev/null
    iptables -D OUTPUT -d "$1" -j DROP 2>/dev/null
    py "
import json
try: d=json.load(open('$BLOCKLIST_FILE')); d.pop('$1',None); json.dump(d,open('$BLOCKLIST_FILE','w'),indent=2); print('  Removed.')
except: print('  Not found.')
"
    echo -e "${GREEN}✅ $1 removed from blocklist and unblocked.${NC}"
}

cmd_blocklist() {
    header
    echo -e "\n  ${BOLD}Permanent Blocklist:${NC}\n"
    py "
import json,time
try: data=json.load(open('$BLOCKLIST_FILE'))
except: data={}
if not data: print('  No IPs in blocklist.'); exit()
print(f\"  {'IP':<22} {'Added':<22} {'Note'}\")
print(f\"  {'─'*22} {'─'*22} {'─'*20}\")
for ip,i in data.items():
    added=time.strftime('%Y-%m-%d %H:%M',time.localtime(i.get('added',0)))
    print(f\"  {ip:<22} {added:<22} {i.get('note','')}\")
print()
"
}

# ── quarantine ────────────────────────────────────────────────────────────────
cmd_quarantine() {
    header
    echo -e "\n  ${BOLD}Quarantined Domains:${NC}\n"
    py "
import json,time
try: data=json.load(open('$QUARANTINE_FILE'))
except: data={}
if not data: print('  No quarantined domains.'); exit()
print(f\"  {'Domain':<35} {'Since':<22} {'Docroot'}\")
print(f\"  {'─'*35} {'─'*22} {'─'*30}\")
for d,i in data.items():
    since=time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(i.get('since',0)))
    print(f\"  {d:<35} {since:<22} {i.get('docroot','?')}\")
print()
"
}

cmd_release() {
    [ -z "$1" ] && echo -e "${RED}Usage: vg release <domain>${NC}" && exit 1
    echo -e "${YELLOW}Releasing quarantine for $1...${NC}"
    py "
import json,os,shutil
try: data=json.load(open('$QUARANTINE_FILE'))
except: print('  No quarantine data.'); exit()
if '$1' not in data: print('  Not in quarantine.'); exit()
i=data['$1']; dr=i.get('docroot')
if not dr: print('  Docroot unknown.'); exit()
ht=os.path.join(dr,'.htaccess')
bk=os.path.join(dr,'.htaccess.ddos_backup')
for f in [os.path.join(dr,'ddos-challenge.php'),os.path.join(dr,'ddos-verify-check.php'),os.path.join(dr,'.ddos_blocked_ips.json'),os.path.join(dr,'.ddos_verified_ips.json')]:
    if os.path.exists(f): os.remove(f)
if os.path.exists(bk): shutil.move(bk,ht)
elif os.path.exists(ht): os.remove(ht)
del data['$1']
json.dump(data,open('$QUARANTINE_FILE','w'),indent=2)
print('  Done.')
"
    echo -e "${GREEN}✅ $1 released from quarantine.${NC}"
}

# ── block / unblock ───────────────────────────────────────────────────────────
cmd_block() {
    [ -z "$1" ] && echo -e "${RED}Usage: vg block <ip>${NC}" && exit 1
    iptables -I INPUT -s "$1" -j DROP 2>/dev/null
    iptables -I OUTPUT -d "$1" -j DROP 2>/dev/null
    py "
import json,time,os
os.makedirs('$BASE',exist_ok=True)
try: d=json.load(open('$BLOCKED_FILE'))
except: d={}
d['$1']={'time':time.time(),'duration':604800,'permanent':False,'label':'7d-manual'}
json.dump(d,open('$BLOCKED_FILE','w'),indent=2)
"
    echo -e "${GREEN}✅ $1 blocked for 7 days.${NC}"
}

cmd_unblock() {
    [ -z "$1" ] && echo -e "${RED}Usage: vg unblock <ip>${NC}" && exit 1
    iptables -D INPUT -s "$1" -j DROP 2>/dev/null
    iptables -D OUTPUT -d "$1" -j DROP 2>/dev/null
    py "
import json
try: d=json.load(open('$BLOCKED_FILE')); d.pop('$1',None); json.dump(d,open('$BLOCKED_FILE','w'),indent=2); print('  Removed.')
except: print('  Not in list.')
"
    echo -e "${GREEN}✅ $1 unblocked.${NC}"
}

# ── log ───────────────────────────────────────────────────────────────────────
cmd_log() { echo -e "${CYAN}━━━━ Live Log (Ctrl+C to exit) ━━━━${NC}"; tail -f "$LOG_FILE"; }

# ── service ───────────────────────────────────────────────────────────────────
cmd_start()   { systemctl start ddos-guard;   echo -e "${GREEN}▶ Started.${NC}"; }
cmd_stop()    { systemctl stop ddos-guard;    echo -e "${YELLOW}⏹ Stopped.${NC}"; }
cmd_restart() { systemctl restart ddos-guard; echo -e "${GREEN}↺ Restarted.${NC}"; }

# ── help ──────────────────────────────────────────────────────────────────────
cmd_help() {
    header; echo ""
    echo -e "  ${BOLD}Usage:${NC} vg <command> [args]"; echo ""
    echo -e "  ${CYAN}Info:${NC}"
    echo -e "    ${GREEN}status${NC}                       Overview + active config"
    echo -e "    ${GREEN}blocked${NC}                      Auto-blocked IPs"
    echo -e "    ${GREEN}quarantine${NC}                   Quarantined domains"
    echo -e "    ${GREEN}log${NC}                          Live log"; echo ""
    echo -e "  ${CYAN}Config:${NC}"
    echo -e "    ${GREEN}config${NC}                       Show all editable keys"
    echo -e "    ${GREEN}config${NC} <key> <value>         Update a config value"; echo ""
    echo -e "  ${CYAN}Whitelist:${NC}"
    echo -e "    ${GREEN}whitelist${NC}                    Show whitelist"
    echo -e "    ${GREEN}whitelist-add${NC} <ip> [note]"
    echo -e "    ${GREEN}whitelist-remove${NC} <ip>"; echo ""
    echo -e "  ${CYAN}Blocklist (permanent):${NC}"
    echo -e "    ${GREEN}blocklist${NC}                    Show blocklist"
    echo -e "    ${GREEN}blocklist-add${NC} <ip> [note]"
    echo -e "    ${GREEN}blocklist-remove${NC} <ip>"; echo ""
    echo -e "  ${CYAN}Manual Actions:${NC}"
    echo -e "    ${GREEN}block${NC} <ip>                   Block IP (7 days)"
    echo -e "    ${GREEN}unblock${NC} <ip>                 Unblock IP"
    echo -e "    ${GREEN}release${NC} <domain>             Release quarantine"; echo ""
    echo -e "  ${CYAN}Service:${NC}"
    echo -e "    ${GREEN}start${NC} / ${GREEN}stop${NC} / ${GREEN}restart${NC}"; echo ""
    echo -e "  ${YELLOW}Config examples:${NC}"
    echo -e "    vg config block_threshold 200"
    echo -e "    vg config server_wide_enabled true"
    echo -e "    vg config server_wide_threshold 50000"
    echo -e "    vg config quarantine_release_at 200"; echo ""
}

# ── router ────────────────────────────────────────────────────────────────────
case "$1" in
    status)           cmd_status ;;
    blocked)          cmd_blocked ;;
    quarantine)       cmd_quarantine ;;
    release)          cmd_release "$2" ;;
    block)            cmd_block "$2" ;;
    unblock)          cmd_unblock "$2" ;;
    whitelist-add)    cmd_whitelist_add "$2" "$3" ;;
    whitelist-remove) cmd_whitelist_remove "$2" ;;
    whitelist)        cmd_whitelist ;;
    blocklist-add)    cmd_blocklist_add "$2" "$3" ;;
    blocklist-remove) cmd_blocklist_remove "$2" ;;
    blocklist)        cmd_blocklist ;;
    config)           cmd_config "$2" "$3" ;;
    log)              cmd_log ;;
    start)            cmd_start ;;
    stop)             cmd_stop ;;
    restart)          cmd_restart ;;
    help|--help|-h)   cmd_help ;;
    *)                cmd_help ;;
esac
