#!/bin/bash
#
# Bitlane VPN Agent Installer
# ============================
# One-liner installation script for VPN node servers.
#
# Usage:
#   curl -sSL https://your-panel.com/install | bash -s -- <API_URL> <API_TOKEN> <WG_PORT> <WG_INTERFACE> <IPV4_POOL> <IPV6_POOL>
#
# Or from the panel's install command:
#   curl -sSL https://your-panel.com/install | bash -s -- https://panel.example.com TOKEN_HERE 51820 wg0 10.11.12.0/24 fddd:573d:9a6f::/48
#

set -euo pipefail

# ─── Colors ──────────────────────────────────────────────────────────────────

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

# ─── Functions ───────────────────────────────────────────────────────────────

log_info()  { echo -e "${GREEN}[✓]${NC} $1"; }
log_warn()  { echo -e "${YELLOW}[!]${NC} $1"; }
log_error() { echo -e "${RED}[✗]${NC} $1"; }
log_step()  { echo -e "${CYAN}[→]${NC} $1"; }

header() {
    echo ""
    echo -e "${CYAN}╔══════════════════════════════════════════╗${NC}"
    echo -e "${CYAN}║       Bitlane VPN Agent Installer        ║${NC}"
    echo -e "${CYAN}║              v1.0.0                      ║${NC}"
    echo -e "${CYAN}╚══════════════════════════════════════════╝${NC}"
    echo ""
}

check_root() {
    if [[ $EUID -ne 0 ]]; then
        log_error "This script must be run as root"
        exit 1
    fi
}

check_os() {
    if [[ ! -f /etc/os-release ]]; then
        log_error "Unsupported operating system"
        exit 1
    fi

    . /etc/os-release
    case "$ID" in
        ubuntu|debian)
            PKG_MANAGER="apt-get"
            PKG_UPDATE="apt-get update -qq"
            PKG_INSTALL="apt-get install -y -qq"
            ;;
        centos|rhel|rocky|almalinux|fedora)
            PKG_MANAGER="yum"
            PKG_UPDATE="yum makecache -q"
            PKG_INSTALL="yum install -y -q"
            ;;
        *)
            log_error "Unsupported OS: $ID"
            exit 1
            ;;
    esac

    log_info "Detected OS: $PRETTY_NAME"
}

# ─── Parse Arguments ────────────────────────────────────────────────────────

API_URL="${1:-}"
API_TOKEN="${2:-}"
WG_PORT="${3:-51820}"
WG_INTERFACE="${4:-wg0}"
IPV4_POOL="${5:-}"
IPV6_POOL="${6:-}"

if [[ -z "$API_URL" || -z "$API_TOKEN" ]]; then
    log_error "Usage: $0 <API_URL> <API_TOKEN> [WG_PORT] [WG_INTERFACE] [IPV4_POOL] [IPV6_POOL]"
    exit 1
fi

# ─── Main Installation ──────────────────────────────────────────────────────

header
check_root
check_os

# Step 1: Install dependencies
log_step "Installing dependencies..."
$PKG_UPDATE > /dev/null 2>&1
$PKG_INSTALL wireguard wireguard-tools python3 curl iptables > /dev/null 2>&1
log_info "Dependencies installed"

# Step 2: Enable IP forwarding
log_step "Enabling IP forwarding..."
sysctl -w net.ipv4.ip_forward=1 > /dev/null 2>&1
sysctl -w net.ipv6.conf.all.forwarding=1 > /dev/null 2>&1

# Persist
if ! grep -q "net.ipv4.ip_forward = 1" /etc/sysctl.conf 2>/dev/null; then
    echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
fi
if ! grep -q "net.ipv6.conf.all.forwarding = 1" /etc/sysctl.conf 2>/dev/null; then
    echo "net.ipv6.conf.all.forwarding = 1" >> /etc/sysctl.conf
fi
log_info "IP forwarding enabled"

# Step 3: Generate WireGuard keys
log_step "Setting up WireGuard..."
WG_PRIVATE_KEY=$(wg genkey)
WG_PUBLIC_KEY=$(echo "$WG_PRIVATE_KEY" | wg pubkey)

# Detect primary network interface
PRIMARY_IFACE=$(ip route show default | awk '/default/ {print $5}' | head -1)
if [[ -z "$PRIMARY_IFACE" ]]; then
    PRIMARY_IFACE="eth0"
fi
log_info "Primary interface: $PRIMARY_IFACE"

# Step 4: Create WireGuard config
log_step "Creating WireGuard configuration..."
mkdir -p /etc/wireguard

cat > "/etc/wireguard/${WG_INTERFACE}.conf" << EOF
[Interface]
PrivateKey = ${WG_PRIVATE_KEY}
Address = 10.0.0.1/24, fd00::1/64
ListenPort = ${WG_PORT}
SaveConfig = true

# NAT / Masquerade
PostUp = iptables -t nat -A POSTROUTING -o ${PRIMARY_IFACE} -j MASQUERADE
PostUp = ip6tables -t nat -A POSTROUTING -o ${PRIMARY_IFACE} -j MASQUERADE
PostDown = iptables -t nat -D POSTROUTING -o ${PRIMARY_IFACE} -j MASQUERADE
PostDown = ip6tables -t nat -D POSTROUTING -o ${PRIMARY_IFACE} -j MASQUERADE
EOF

chmod 600 "/etc/wireguard/${WG_INTERFACE}.conf"
log_info "WireGuard config created"

# Step 5: Start WireGuard
log_step "Starting WireGuard interface..."
systemctl enable "wg-quick@${WG_INTERFACE}" > /dev/null 2>&1
wg-quick up "$WG_INTERFACE" 2>/dev/null || true
log_info "WireGuard interface ${WG_INTERFACE} is up"

# Step 6: Install Bitlane agent
log_step "Installing Bitlane agent..."
INSTALL_DIR="/opt/bitlane"
CONFIG_DIR="/etc/bitlane"

mkdir -p "$INSTALL_DIR" "$CONFIG_DIR" /var/log

# Download agent script from panel
AGENT_DOWNLOAD_URL="${API_URL}/agent/download"

# Try to download, fallback to embedded
if curl -sSfL -H "Authorization: Bearer ${API_TOKEN}" "${AGENT_DOWNLOAD_URL}" -o "${INSTALL_DIR}/bitlane-agent.py" 2>/dev/null; then
    log_info "Agent downloaded from panel"
else
    log_warn "Could not download agent from panel, using embedded version"
    # Write embedded agent (minimal fallback)
    cat > "${INSTALL_DIR}/bitlane-agent.py" << 'AGENT_EOF'
#!/usr/bin/env python3
"""Bitlane Agent - Minimal fallback. Update from panel recommended."""
import os, sys, json, time, subprocess, threading, signal, logging, hashlib
from urllib.request import Request, urlopen
from urllib.error import URLError, HTTPError

CONFIG_FILE = "/etc/bitlane/agent.conf"
LOG_FILE = "/var/log/bitlane-agent.log"
VERSION = "1.0.0"

logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s",
    handlers=[logging.FileHandler(LOG_FILE), logging.StreamHandler(sys.stdout)])
logger = logging.getLogger("bitlane-agent")

class Config:
    def __init__(self):
        with open(CONFIG_FILE) as f: self.data = json.load(f)
    def get(self, k, d=None): return self.data.get(k, d)
    @property
    def api_url(self): return self.data.get("api_url","").rstrip("/")
    @property
    def api_token(self): return self.data.get("api_token","")
    @property
    def wg_interface(self): return self.data.get("wg_interface","wg0")

def api_post(config, endpoint, data=None):
    url = f"{config.api_url}/api/agent/{endpoint}"
    headers = {"Authorization": f"Bearer {config.api_token}", "Content-Type": "application/json", "Accept": "application/json"}
    body = json.dumps(data).encode() if data else None
    try:
        with urlopen(Request(url, data=body, headers=headers, method="POST"), timeout=30) as r:
            return json.loads(r.read().decode())
    except: return None

def api_get(config, endpoint):
    url = f"{config.api_url}/api/agent/{endpoint}"
    headers = {"Authorization": f"Bearer {config.api_token}", "Accept": "application/json"}
    try:
        with urlopen(Request(url, headers=headers), timeout=30) as r:
            return json.loads(r.read().decode())
    except: return None

def run(cmd):
    try:
        r = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=30)
        return r.stdout.strip() if r.returncode == 0 else None
    except: return None

def main():
    if os.geteuid() != 0: print("Must run as root"); sys.exit(1)
    config = Config()
    iface = config.wg_interface
    prev_stats = {}
    running = True
    def stop(s, f): nonlocal running; running = False
    signal.signal(signal.SIGTERM, stop); signal.signal(signal.SIGINT, stop)
    logger.info(f"Bitlane Agent v{VERSION} started")

    while running:
        # Heartbeat
        pubkey = run(f"wg show {iface} public-key")
        peers = run(f"wg show {iface} transfer")
        peer_count = len(peers.strip().split("\n")) if peers else 0
        api_post(config, "heartbeat", {"status":"online","version":VERSION,"public_key":pubkey,"active_peers":peer_count})

        # Traffic
        current = {}
        if peers:
            for line in peers.strip().split("\n"):
                p = line.split("\t")
                if len(p) >= 3: current[p[0]] = {"rx": int(p[1]), "tx": int(p[2])}
        deltas = []
        for pk, s in current.items():
            if pk in prev_stats:
                du, dd = max(0, s["rx"]-prev_stats[pk]["rx"]), max(0, s["tx"]-prev_stats[pk]["tx"])
                if du > 0 or dd > 0: deltas.append({"public_key":pk,"bytes_up":du,"bytes_down":dd})
        prev_stats = current
        if deltas: api_post(config, "report-traffic", {"peers": deltas})

        # Commands
        cmds = api_get(config, "pending-commands")
        if cmds:
            for p in cmds.get("pending_profiles", []):
                priv, pub = run("wg genkey"), None
                if priv: pub = run(f"echo '{priv}' | wg pubkey")
                if pub:
                    psk = run("wg genpsk") or ""
                    ips = p.get("allowed_ips","")
                    run(f"wg set {iface} peer {pub} allowed-ips {ips}")
                    run(f"wg-quick save {iface}")
                    api_post(config, "confirm-peer", {"profile_id":p["id"],"public_key":pub,"private_key":priv,"preshared_key":psk})
            for pk in cmds.get("to_block", []):
                run(f"wg set {iface} peer {pk} remove"); run(f"wg-quick save {iface}")
            for peer in cmds.get("to_activate", []):
                if peer.get("public_key") and peer.get("allowed_ips"):
                    run(f"wg set {iface} peer {peer['public_key']} allowed-ips {peer['allowed_ips']}")
                    run(f"wg-quick save {iface}")

        time.sleep(30)

if __name__ == "__main__": main()
AGENT_EOF
fi

chmod +x "${INSTALL_DIR}/bitlane-agent.py"

# Step 7: Create config
log_step "Creating agent configuration..."
cat > "${CONFIG_DIR}/agent.conf" << EOF
{
    "api_url": "${API_URL}",
    "api_token": "${API_TOKEN}",
    "wg_interface": "${WG_INTERFACE}",
    "wg_config_dir": "/etc/wireguard",
    "wg_listen_port": ${WG_PORT},
    "network_interface": "${PRIMARY_IFACE}",
    "ipv4_pool": "${IPV4_POOL}",
    "ipv6_pool": "${IPV6_POOL}"
}
EOF

chmod 600 "${CONFIG_DIR}/agent.conf"
log_info "Configuration saved"

# Step 8: Create systemd service
log_step "Creating systemd service..."
cat > /etc/systemd/system/bitlane-agent.service << EOF
[Unit]
Description=Bitlane VPN Agent
After=network.target wg-quick@${WG_INTERFACE}.service
Wants=wg-quick@${WG_INTERFACE}.service

[Service]
Type=simple
ExecStart=/usr/bin/python3 ${INSTALL_DIR}/bitlane-agent.py
Restart=always
RestartSec=10
StandardOutput=journal
StandardError=journal
SyslogIdentifier=bitlane-agent

# Security hardening
NoNewPrivileges=no
ProtectSystem=false

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable bitlane-agent > /dev/null 2>&1
systemctl start bitlane-agent
log_info "Systemd service created and started"

# ─── Done ────────────────────────────────────────────────────────────────────

echo ""
echo -e "${GREEN}╔══════════════════════════════════════════╗${NC}"
echo -e "${GREEN}║    Bitlane Agent Installed Successfully   ║${NC}"
echo -e "${GREEN}╚══════════════════════════════════════════╝${NC}"
echo ""
echo -e "  ${CYAN}WG Interface:${NC}  ${WG_INTERFACE}"
echo -e "  ${CYAN}WG Port:${NC}       ${WG_PORT}"
echo -e "  ${CYAN}Public Key:${NC}    ${WG_PUBLIC_KEY}"
echo -e "  ${CYAN}Primary NIC:${NC}   ${PRIMARY_IFACE}"
echo -e "  ${CYAN}Agent Log:${NC}     /var/log/bitlane-agent.log"
echo ""
echo -e "  ${YELLOW}Commands:${NC}"
echo -e "    systemctl status bitlane-agent"
echo -e "    journalctl -u bitlane-agent -f"
echo -e "    wg show ${WG_INTERFACE}"
echo ""
