#!/usr/bin/env bash
# ╔════════════════════════════════════════════════════════════════════╗
# ║  TunnelForge Pro — Enterprise SSH Tunnel Manager                  ║
# ║  Version : 2.0.0 (Pro Edition)                                    ║
# ║  Author  : SamNet Technologies, LLC                               ║
# ╚════════════════════════════════════════════════════════════════════╝

set -eo pipefail
# فعال‌سازی تله‌پورت خطا برای توابع فرعی (Trap Stack)
set -E 

# ============================================================================
# GLOBAL CONSTANTS & PATHS
# ============================================================================

readonly VERSION="2.0.0"
readonly APP_NAME="TunnelForge"
readonly INSTALL_DIR="/opt/tunnelforge"
readonly CONFIG_DIR="${INSTALL_DIR}/config"
readonly PROFILES_DIR="${INSTALL_DIR}/profiles"
readonly PID_DIR="${INSTALL_DIR}/pids"
readonly LOG_DIR="${INSTALL_DIR}/logs"
readonly TMP_DIR="/tmp/tunnelforge_tmp"
readonly SSH_CONTROL_DIR="${INSTALL_DIR}/sockets"
readonly MAIN_CONFIG="${CONFIG_DIR}/tunnelforge.conf"

# ============================================================================
# 1. ADVANCED ERROR HANDLING (TRAP STACK)
# ============================================================================

cleanup() {
    local exit_code=$?
    # غیرفعال کردن ترپ برای جلوگیری از حلقه بی‌نهایت در زمان خطا
    trap - ERR EXIT INT TERM
    
    # پاکسازی منابع
    tput cnorm 2>/dev/null || true
    [[ -d "$TMP_DIR" ]] && rm -rf "$TMP_DIR"
    
    # توقف داشبورد وب
    stop_web_dashboard &>/dev/null || true
    
    exit ${exit_code}
}

__error_handler() {
    local exit_code=$?
    local line_no=$1
    local bash_command="${BASH_COMMAND}"
    local func_trace=$(printf " -> %s" "${FUNCNAME[@]:1}")
    
    local ts; ts=$(date -u '+%Y-%m-%dT%H:%M:%SZ')
    
    # خروجی خطا به stderr و فایل لاگ
    echo -e "\n[${RED}CRITICAL${RESET}] Error on line ${line_no}" >&2
    echo "Command: ${bash_command}" >&2
    echo "Exit Code: ${exit_code}" >&2
    echo "Stack Trace:${func_trace}" >&2

    if [[ -w "${LOG_DIR}" ]]; then
        echo "[${ts}] CRITICAL: Line ${line_no} cmd '${bash_command}' failed (${exit_code})" >> "${LOG_DIR}/tunnelforge.log"
    fi

    # ارسال هشدار تلگرام (غیرمسدودکننده)
    if type _telegram_notify &>/dev/null; then
        _telegram_notify "🚨 CRASH: Line ${line_no} failed" &
    fi
    
    cleanup
    exit ${exit_code}
}

trap '__error_handler ${LINENO}' ERR
trap 'cleanup' EXIT INT TERM

# ============================================================================
# 2. COLOR & LOGGING SETUP
# ============================================================================

if [[ -t 1 ]] && [[ -z "${NO_COLOR:-}" ]]; then
    RED=$'\033[0;31m'; GREEN=$'\033[0;32m'; YELLOW=$'\033[0;33m'; CYAN=$'\033[0;36m'
    BOLD=$'\033[1m'; RESET=$'\033[0m'
else
    RED=''; GREEN=''; YELLOW=''; CYAN=''; BOLD=''; RESET=''
fi

log() { printf "${CYAN}[INFO]${RESET} %s\n" "$1"; }
log_warn() { printf "${YELLOW}[WARN]${RESET} %s\n" "$1"; }
log_error() { printf "${RED}[ERROR]${RESET} %s\n" "$1" >&2; }
log_success() { printf "${GREEN}[OK]${RESET} %s\n" "$1"; }

# ============================================================================
# 3. CONFIGURATION & DEPENDENCIES
# ============================================================================

declare -gA CONFIG=(
    [SSH_DEFAULT_USER]="root"
    [SSH_DEFAULT_PORT]="22"
    [AUTOSSH_ENABLED]="true"
    [DNS_LEAK_PROTECTION]="false"
    [KILL_SWITCH]="false"
    
    # Pro Features Defaults
    [WEB_DASHBOARD_ENABLED]="false"
    [WEB_DASHBOARD_PORT]="8080"
    [WEB_DASHBOARD_BIND]="127.0.0.1"
    
    [SPLIT_TUNNELING_ENABLED]="false"
    [SPLIT_TUNNEL_ROUTES]="" 
    
    [OBFS_MODE]="none" # none | stunnel | shadowsocks
    [OBFS_PORT]="443"
    [OBFS_PSK]=""
    
    [LOG_JSON]="false"
)

# متغیرهای سراسری برای محاسبه پهنای باند
declare -gA _BW_BYTES_PREV=()
declare -gA _BW_TIME_PREV=()

config_get() {
    local key="$1"
    local default="${2:-}"
    echo "${CONFIG[$key]:-$default}"
}

init_dirs() {
    mkdir -p "$INSTALL_DIR" "$CONFIG_DIR" "$PROFILES_DIR" "$PID_DIR" "$LOG_DIR" "$TMP_DIR" "$SSH_CONTROL_DIR"
    chmod 700 "$CONFIG_DIR" "$PROFILES_DIR" "$PID_DIR" 2>/dev/null
}

# تشخیص محیط داکر
detect_docker() {
    if [[ -f "/.dockerenv" ]] || grep -q 'docker\|lxc' /proc/1/cgroup 2>/dev/null; then
        export IS_DOCKER=true
        log_warn "Docker environment detected. Adjusting paths..."
        # در داکر معمولاً systemd وجود ندارد
        export INIT_SYSTEM="none"
    else
        export IS_DOCKER=false
        # تشخیص systemd
        if command -v systemctl &>/dev/null && [[ -d /run/systemd/system ]]; then
            export INIT_SYSTEM="systemd"
        else
            export INIT_SYSTEM="other"
        fi
    fi
}

check_deps() {
    local missing=()
    local -A deps=(
        [ssh]="openssh-client"
        [ip]="iproute2"
        [iptables]="iptables"
        # ابزارهای پرو
        [socat]="socat"               # Web Dashboard
        [ss-local]="shadowsocks-libev" # Obfuscation (Might be named differently)
        [jq]="jq"
    )

    for cmd in "${!deps[@]}"; do
        if ! command -v "$cmd" &>/dev/null; then
            # بررسی نام‌های جایگزین برای shadowsocks
            if [[ "$cmd" == "ss-local" ]] && command -v ss-local &>/dev/null; then
                : # found
            else
                missing+=("${deps[$cmd]}")
            fi
        fi
    done

    if [[ ${#missing[@]} -gt 0 ]]; then
        log_error "Missing dependencies: ${missing[*]}"
        log "Try: sudo apt install ${missing[*]} (or equivalent)"
        return 1
    fi
}

# ============================================================================
# 4. PRO FEATURES IMPLEMENTATION
# ============================================================================

# --- 4.1 Systemd Watchdog ---
_systemd_notify() {
    local status="$1"
    # بررسی وجود سوکت notify
    if [[ -S "${NOTIFY_SOCKET:-}" ]]; then
        printf "STATUS=%s\nREADY=1\nWATCHDOG=1\n" "$status" | socat - UNIX-SENDTO:"${NOTIFY_SOCKET}" 2>/dev/null || true
    fi
}

# --- 4.2 IPv6 Native Support ---
get_ssh_ip_version_flag() {
    local host="$1"
    # اگر هاست شامل : باشد (IPv6)، پرچم -6 را برگردان
    if [[ "$host" =~ : ]]; then
        echo "-6"
    fi
}

# --- 4.3 Bandwidth Monitoring (Realtime) ---
_setup_bandwidth_accounting() {
    local name="$1"
    local port="$2"
    local chain="TF_BW_${name}"
    
    # ایجاد زنجیره اختصاصی اگر وجود نداشته باشد
    if ! iptables -L "$chain" -n 2>/dev/null; then
        iptables -N "$chain" 2>/dev/null || return 1
    fi
    
    # افزودن قوانین شمارش (جلوگیری از تکرار)
    iptables -C INPUT -p tcp --dport "$port" -j "$chain" 2>/dev/null || iptables -A INPUT -p tcp --dport "$port" -j "$chain"
    iptables -C OUTPUT -p tcp --sport "$port" -j "$chain" 2>/dev/null || iptables -A OUTPUT -p tcp --sport "$port" -j "$chain"
}

get_tunnel_bandwidth_realtime() {
    local name="$1"
    local chain="TF_BW_${name}"
    
    # استخراج بایت‌های شمارش شده
    local rx_bytes tx_bytes
    rx_bytes=$(iptables -L "$chain" -vnx 2>/dev/null | grep "INPUT" | awk '{print $2}')
    tx_bytes=$(iptables -L "$chain" -vnx 2>/dev/null | grep "OUTPUT" | awk '{print $2}')
    
    [[ -z "$rx_bytes" ]] && rx_bytes=0
    [[ -z "$tx_bytes" ]] && tx_bytes=0

    # محاسبه سرعت (bps)
    local now_ts=$(date +%s)
    local prev_time="${_BW_TIME_PREV[$name]:-$now_ts}"
    local prev_rx="${_BW_BYTES_PREV[${name}_rx]:-0}"
    local prev_tx="${_BW_BYTES_PREV[${name}_tx]:-0}"
    
    local dt=$(( now_ts - prev_time ))
    if (( dt == 0 )); then dt=1; fi
    
    local rx_rate=$(( (rx_bytes - prev_rx) * 8 / dt )) 
    local tx_rate=$(( (tx_bytes - prev_tx) * 8 / dt ))

    # به‌روزرسانی کش
    _BW_TIME_PREV[$name]="$now_ts"
    _BW_BYTES_PREV[${name}_rx]="$rx_bytes"
    _BW_BYTES_PREV[${name}_tx]="$tx_bytes"

    # خروجی: "Total_RX Total_TX Rate_RX Rate_TX"
    echo "${rx_bytes} ${tx_bytes} ${rx_rate} ${tx_rate}"
}

# --- 4.4 Split Tunneling ---
enable_split_tunneling() {
    local name="$1"
    local routes="${2:-}" 
    
    if [[ -z "$routes" ]]; then return 0; fi
    if ! command -v ip &>/dev/null; then log_error "iproute2 required"; return 1; fi

    # ایجاد جدول روتینگ اختصاصی
    local table_id="200${RANDOM}"
    local table_file="/etc/iproute2/rt_tables"
    
    if ! grep -q "tf_${name}" "$table_file" 2>/dev/null; then
        echo "${table_id} tf_${name}" >> "$table_file"
    fi

    # پاکسازی قوانین قبلی
    ip rule del table "tf_${name}" 2>/dev/null || true
    
    IFS=',' read -ra ADDR <<< "$routes"
    for ip_route in "${ADDR[@]}"; do
        log "Split Tunnel: Routing $ip_route via table tf_${name}"
        ip rule add to "$ip_route" table "tf_${name}" priority 100 2>/dev/null || log_warn "Failed to add rule for $ip_route"
    done
    
    log_success "Split Tunneling active."
}

disable_split_tunneling() {
    local name="$1"
    ip rule del table "tf_${name}" 2>/dev/null || true
    sed -i "/tf_${name}/d" /etc/iproute2/rt_tables 2>/dev/null || true
}

# --- 4.5 Advanced Obfuscation (Shadowsocks) ---
build_shadowsocks_cmd() {
    local name="$1"
    local -n _prof_ref="$2"
    
    local local_port="${_prof_ref[LOCAL_PORT]}"
    local server="${_prof_ref[SSH_HOST]}"
    local remote_port="${_prof_ref[OBFS_PORT]}"
    local pass="${_prof_ref[OBFS_PSK]}"
    
    if [[ -z "$pass" ]]; then
        log_error "OBFS_PSK not set for Shadowsocks mode."
        return 1
    fi

    # فایل کانفیگ موقت
    local conf="${TMP_DIR}/ss-${name}.json"
    cat > "$conf" <<EOF
{
    "server":"${server}",
    "server_port":${remote_port},
    "local_port":${local_port},
    "password":"${pass}",
    "timeout":60,
    "method":"aes-256-gcm"
}
EOF
    echo "ss-local -c ${conf} -v"
}

# --- 4.6 Web Dashboard ---
start_web_dashboard() {
    local port=$(config_get WEB_DASHBOARD_PORT 8080)
    local bind=$(config_get WEB_DASHBOARD_BIND "127.0.0.1")
    
    if [[ "$(config_get WEB_DASHBOARD_ENABLED)" != "true" ]]; then return 0; fi
    if ! command -v socat &>/dev/null; then log_warn "Socat not found, dashboard disabled."; return 1; fi

    log "Starting Web Dashboard on http://${bind}:${port}"
    
    # توقف نمونه قبلی
    stop_web_dashboard

    # اجرای سرور در پس‌زمینه
    (
        while true; do
            local html_file="${TMP_DIR}/dashboard.html"
            {
                echo -e "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n"
                echo "<html><head><meta http-equiv='refresh' content='3'><title>TF Pro</title>"
                echo "<style>body{font-family:monospace;background:#111;color:#0f0;} table{width:100%;border-collapse:collapse;} th,td{border:1px solid #333;padding:5px;}</style></head><body>"
                echo "<h1>TunnelForge Pro Dashboard</h1>"
                echo "<h3>Active Tunnels</h3><table><tr><th>Name</th><th>Status</th><th>PID</th><th>RX (bps)</th><th>TX (bps)</th></tr>"
                
                for profile_file in "${PROFILES_DIR}"/*.conf; do
                    [[ -f "$profile_file" ]] || continue
                    local pname=$(basename "$profile_file" .conf)
                    
                    local pid="-"; local status="STOPPED"; local color="#f00"
                    local pid_file="${PID_DIR}/${pname}.pid"
                    local rx="0"; local tx="0"
                    
                    if [[ -f "$pid_file" ]]; then
                        pid=$(cat "$pid_file")
                        if kill -0 "$pid" 2>/dev/null; then
                            status="ACTIVE"; color="#0f0"
                            # دریافت ترافیک
                            local bw_str
                            bw_str=$(get_tunnel_bandwidth_realtime "$pname")
                            rx=$(echo "$bw_str" | awk '{print $3}')
                            tx=$(echo "$bw_str" | awk '{print $4}')
                        else
                            status="DEAD"
                        fi
                    fi
                    echo "<tr><td>${pname}</td><td style='color:${color}'>${status}</td><td>${pid}</td><td>${rx}</td><td>${tx}</td></tr>"
                done
                
                echo "</table><br><small>Generated: $(date)</small></body></html>"
            } > "$html_file"

            # ارسال فایل با socat
            socat TCP-LISTEN:${port},bind=${bind},fork,reuseaddr OPEN:"$html_file" 2>/dev/null
        done
    ) &
    echo $! > "${PID_DIR}/web_dashboard.pid"
    disown
}

stop_web_dashboard() {
    local pid_file="${PID_DIR}/web_dashboard.pid"
    if [[ -f "$pid_file" ]]; then
        kill $(cat "$pid_file") 2>/dev/null || true
        rm -f "$pid_file"
    fi
}

# ============================================================================
# 5. PROFILE & TUNNEL LOGIC (INTEGRATED)
# ============================================================================

# بارگذاری پروفایل (ساده شده برای مثال - باید با کد اصلی جایگزین شود)
load_profile() {
    local name="$1"
    local -n prof_ref="$2"
    local profile_file="${PROFILES_DIR}/${name}.conf"
    
    if [[ ! -f "$profile_file" ]]; then return 1; fi
    
    # پارس کردن ساده فایل کانفیگ
    while IFS='=' read -r key value; do
        # حذف کوتیشن‌ها
        value="${value%\"}"; value="${value#\"}"
        prof_ref["$key"]="$value"
    done < <(grep -v '^#' "$profile_file")
    
    # مقادیر پیش‌فرض
    prof_ref[LOCAL_PORT]=${prof_ref[LOCAL_PORT]:-1080}
    prof_ref[OBFS_MODE]=${prof_ref[OBFS_MODE]:-none}
    prof_ref[OBFS_PORT]=${prof_ref[OBFS_PORT]:-443}
}

# تابع اصلی ساخت دستور تونل
build_tunnel_cmd_pro() {
    local name="$1"
    local -A _prof
    load_profile "$name" _prof || return 1

    local obfs_mode="${_prof[OBFS_MODE]}"
    local ssh_host="${_prof[SSH_HOST]}"
    local local_port="${_prof[LOCAL_PORT]}"
    
    # فلگ IPv6
    local ip_flag=$(get_ssh_ip_version_flag "$ssh_host")

    case "$obfs_mode" in
        shadowsocks)
            build_shadowsocks_cmd "$name" _prof
            ;;
        stunnel)
            # اینجا باید لاجیک stunnel اضافه شود
            # برای مثال: echo "stunnel ..." 
            log_error "Stunnel logic not implemented in this snippet."
            return 1
            ;;
        *)
            # حالت پیش‌فرض SSH
            # ایجاد دستور SSH با پشتیبانی از IPv6
            local ssh_user="${_prof[SSH_USER]:-root}"
            echo "ssh ${ip_flag} -N -T -D 0.0.0.0:${local_port} ${ssh_user}@${ssh_host}"
            ;;
    esac
}

# تابع استارت تونل (یکپارچه)
start_tunnel_pro() {
    local name="$1"
    local -A _prof
    if ! load_profile "$name" _prof; then
        log_error "Profile '$name' not found."
        return 1
    fi

    local pid_file="${PID_DIR}/${name}.pid"
    if [[ -f "$pid_file" ]] && kill -0 $(cat "$pid_file") 2>/dev/null; then
        log_warn "Tunnel '$name' is already running."
        return 0
    fi

    log "Starting tunnel '$name'..."

    # ساخت دستور
    local cmd
    cmd=$(build_tunnel_cmd_pro "$name") || return 1

    # اجرا در پس‌زمینه
    # نکته: برای Shadowsocks، دستور مستقیماً ss-local را اجرا می‌کند
    # برای SSH، دستور ssh را اجرا می‌کند.
    
    if [[ "${_prof[OBFS_MODE]}" == "shadowsocks" ]]; then
        # اجرای ss-local
        log "Running Shadowsocks client..."
        eval "$cmd" &>> "${LOG_DIR}/${name}.log" &
    else
        # اجرای SSH
        log "Running SSH tunnel..."
        eval "$cmd" &>> "${LOG_DIR}/${name}.log" &
    fi
    
    local pid=$!
    disown $pid
    echo $pid > "$pid_file"
    
    # منتظر ماندن برای اطمینان از بالا آمدن پورت
    sleep 2
    if ! kill -0 $pid 2>/dev/null; then
        log_error "Failed to start process. Check logs."
        rm -f "$pid_file"
        return 1
    fi

    # --- فعال‌سازی ویژگی‌های پرو ---

    # 1. Accounting (پهنای باند)
    # نکته: برای SSH SOCKS، پورت لوکال استفاده می‌شود. برای Shadowsocks هم پورت لوکال.
    _setup_bandwidth_accounting "$name" "${_prof[LOCAL_PORT]}"

    # 2. Split Tunneling
    if [[ "${_prof[SPLIT_TUNNELING_ENABLED]}" == "true" ]]; then
        enable_split_tunneling "$name" "${_prof[SPLIT_TUNNEL_ROUTES]}"
    fi

    # 3. Systemd Notify
    _systemd_notify "Tunnel ${name} active (PID: ${pid})"

    log_success "Tunnel '$name' started successfully (PID: ${pid})."
}

stop_tunnel_pro() {
    local name="$1"
    local pid_file="${PID_DIR}/${name}.pid"
    
    if [[ ! -f "$pid_file" ]]; then
        log_warn "Tunnel '$name' is not running."
        return 0
    fi

    local pid=$(cat "$pid_file")
    if kill -0 "$pid" 2>/dev/null; then
        log "Stopping tunnel '$name' (PID: ${pid})..."
        kill "$pid"
        # منتظر خاموش شدن
        local count=0
        while kill -0 "$pid" 2>/dev/null && [[ $count -lt 10 ]]; do
            sleep 1; ((count++))
        done
        if kill -0 "$pid" 2>/dev/null; then
            kill -9 "$pid"
        fi
    fi
    
    rm -f "$pid_file"

    # --- غیرفعال‌سازی ویژگی‌های پرو ---
    
    # حذف قوانین Accounting
    local chain="TF_BW_${name}"
    iptables -D INPUT -j "$chain" 2>/dev/null || true
    iptables -D OUTPUT -j "$chain" 2>/dev/null || true
    iptables -F "$chain" 2>/dev/null || true
    iptables -X "$chain" 2>/dev/null || true

    # غیرفعال‌سازی Split Tunneling
    if type disable_split_tunneling &>/dev/null; then
        disable_split_tunneling "$name"
    fi

    log_success "Tunnel '$name' stopped."
}

# ============================================================================
# 6. MAIN CLI LOGIC
# ============================================================================

usage() {
    echo "Usage: $0 [command] [profile]"
    echo "Commands:"
    echo "  start <name>    Start a tunnel"
    echo "  stop <name>     Stop a tunnel"
    echo "  status          Show status"
    echo "  dashboard       Start/Stop web dashboard (if configured)"
    exit 1
}

main() {
    # مقداردهی اولیه
    init_dirs
    detect_docker
    check_deps || exit 1
    
    # بارگذاری تنظیمات اصلی
    if [[ -f "$MAIN_CONFIG" ]]; then
        while IFS='=' read -r key value; do
            CONFIG["$key"]="$value"
        done < <(grep -v '^#' "$MAIN_CONFIG")
    fi

    # اجرای داشبورد وب در صورت فعال بودن (به عنوان سرویس پس‌زمینه)
    if [[ "$(config_get WEB_DASHBOARD_ENABLED)" == "true" ]]; then
        start_web_dashboard
    fi

    # پارس آرگومان‌ها
    local cmd="${1:-}"
    local arg="${2:-}"

    case "$cmd" in
        start)
            if [[ -z "$arg" ]]; then usage; fi
            start_tunnel_pro "$arg"
            ;;
        stop)
            if [[ -z "$arg" ]]; then usage; fi
            stop_tunnel_pro "$arg"
            ;;
        status)
            # نمایش وضعیت ساده
            for pfile in "${PROFILES_DIR}"/*.conf; do
                [[ -f "$pfile" ]] || continue
                local pname=$(basename "$pfile" .conf)
                local pfile_pid="${PID_DIR}/${pname}.pid"
                if [[ -f "$pfile_pid" ]] && kill -0 $(cat "$pfile_pid") 2>/dev/null; then
                    local bw=$(get_tunnel_bandwidth_realtime "$pname")
                    echo "${pname}: RUNNING (RX: $(echo $bw | awk '{print $3}') bps)"
                else
                    echo "${pname}: STOPPED"
                fi
            done
            ;;
        *)
            usage
            ;;
    esac
}

# اجرای اصلی
main "$@"