#!/bin/bash
# ==========================================
# AEA SERVER MODULE: SMART GATEWAY COMMANDER
# VERSION: 1.14 (Global Multi-Zone, Auto-Geo & Custom Ports)
# ==========================================
AEA_VERSION="1.14"
MODULE_DATE="2026-05-17"

INFO_FILE="/etc/aea_gateway.info"
DATA_DIR="/opt/aea_gateway"

# 1. ПОДХВАТЫВАЕМ ПОРТ ИЗ ПЕРЕМЕННОЙ ШАБЛОНА
BASE_INBOUND_PORT="{{APP_PORT_GATEWAY}}"
# Если шаблон не заменен (запуск вручную), ставим порт по умолчанию 41443
[[ "$BASE_INBOUND_PORT" == "{{"* ]] && BASE_INBOUND_PORT=41443

GATEWAY_MODE="{{GATEWAY_MODE}}"
[[ "$GATEWAY_MODE" == "{{"* ]] && GATEWAY_MODE="to_vpn"

BYPASS_ZONE="{{BYPASS_ZONE}}"
[[ "$BYPASS_ZONE" == "{{"* ]] && BYPASS_ZONE="auto"

NEXT_HOP_IP="{{NEXT_HOP_IP}}"
NEXT_HOP_PORT="{{NEXT_HOP_PORT}}"
NEXT_HOP_UUID="{{NEXT_HOP_UUID}}"
NEXT_HOP_SNI="{{NEXT_HOP_SNI}}"
[[ "$NEXT_HOP_SNI" == "{{"* ]] && NEXT_HOP_SNI="bing.com"
NEXT_HOP_PBK="{{NEXT_HOP_PBK}}"
NEXT_HOP_SID="{{NEXT_HOP_SID}}"

generate_route_rules() {
    local mode=$1
    local zone=$2
    local suffixes="[\".$zone\"]"

    if [ "$zone" == "ru" ]; then
        suffixes="[\".ru\", \".su\", \".xn--p1ai\", \"vk.com\", \"yandex.net\", \"yandex.ru\", \"mail.ru\", \"gosuslugi.ru\", \"kinopoisk.ru\"]"
    elif [ "$zone" == "ir" ]; then
        suffixes="[\".ir\", \"sanjesh.org\", \"divar.ir\", \"snapp.ir\", \"shaparak.ir\"]"
    elif [ "$zone" == "cn" ]; then
        suffixes="[\".cn\", \"baidu.com\", \"taobao.com\", \"qq.com\", \"alipay.com\"]"
    fi

    if [ "$mode" == "to_vpn" ]; then
        echo "[
            { \"inbound\": [\"inbound-vless\"], \"action\": \"sniff\" },
            { \"domain_suffix\": $suffixes, \"outbound\": \"direct-out\" },
            { \"rule_set\": [\"geoip-$zone\"], \"outbound\": \"direct-out\" },
            { \"inbound\": [\"inbound-vless\"], \"network\": \"tcp\", \"outbound\": \"tunnel-next-hop\" },
            { \"inbound\": [\"inbound-vless\"], \"network\": \"udp\", \"outbound\": \"tunnel-next-hop\" }
        ]"
    else
        echo "[
            { \"inbound\": [\"inbound-vless\"], \"action\": \"sniff\" },
            { \"inbound\": [\"inbound-vless\"], \"network\": \"tcp\", \"outbound\": \"tunnel-next-hop\" },
            { \"inbound\": [\"inbound-vless\"], \"network\": \"udp\", \"outbound\": \"tunnel-next-hop\" }
        ]"
    fi
}

if [ "$1" == "--version" ] || [ "$1" == "-v" ]; then
    echo "$AEA_VERSION"
    exit 0
fi

if [ "$1" == "--info" ]; then
    if [ -f "$INFO_FILE" ]; then
        base64 -d "$INFO_FILE"
    else
        echo '{"status": "not_installed"}'
    fi
    exit 0
fi

if [ "$1" == "--cli" ]; then
    if [ ! -f "$DATA_DIR/config.json" ]; then
        echo "[AEA] Error: Gateway module is not configured."
        exit 1
    fi

    case $2 in
        add_client)
            NEW_UUID=$(cat /proc/sys/kernel/random/uuid)
            jq --arg uuid "$NEW_UUID" '.inbounds[0].users += [{"uuid": $uuid, "flow": "xtls-rprx-vision"}]' "$DATA_DIR/config.json" > "$DATA_DIR/tmp.json" && mv "$DATA_DIR/tmp.json" "$DATA_DIR/config.json"
            docker restart aea_smart_gateway >/dev/null 2>&1
            echo "{\"status\": \"success\", \"uuid\": \"$NEW_UUID\"}"
            ;;
        remove_client)
            DEL_UUID=$3
            jq --arg uuid "$DEL_UUID" '.inbounds[0].users |= map(select(.uuid != $uuid))' "$DATA_DIR/config.json" > "$DATA_DIR/tmp.json" && mv "$DATA_DIR/tmp.json" "$DATA_DIR/config.json"
            docker restart aea_smart_gateway >/dev/null 2>&1
            echo "{\"status\": \"success\"}"
            ;;
        set_mode)
            NEW_MODE=$3
            CURRENT_INFO=$(base64 -d "$INFO_FILE")
            CURRENT_ZONE=$(echo "$CURRENT_INFO" | jq -r '.bypass_zone')
            RULES=$(generate_route_rules "$NEW_MODE" "$CURRENT_ZONE")
            jq --argjson rules "$RULES" '.route.rules = $rules' "$DATA_DIR/config.json" > "$DATA_DIR/tmp.json" && mv "$DATA_DIR/tmp.json" "$DATA_DIR/config.json"
            docker restart aea_smart_gateway >/dev/null 2>&1
            UPDATED_INFO=$(echo "$CURRENT_INFO" | jq --arg mode "$NEW_MODE" '.mode = $mode')
            echo "$UPDATED_INFO" | base64 > "$INFO_FILE"
            echo "{\"status\": \"success\", \"mode\": \"$NEW_MODE\"}"
            ;;
    esac
    exit 0
fi

if [ "$1" == "--remove" ]; then
    echo "[AEA] Removing Smart Gateway components..."
    if [ -f "$INFO_FILE" ]; then
        JSON=$(base64 -d "$INFO_FILE")
        OLD_PORT=$(echo "$JSON" | grep -oP '"inbound_port": \K\d+')
        if command -v ufw >/dev/null 2>&1; then
            [ -n "$OLD_PORT" ] && ufw delete allow "$OLD_PORT"/tcp >/dev/null 2>&1
            [ -n "$OLD_PORT" ] && ufw delete allow "$OLD_PORT"/udp >/dev/null 2>&1
        fi
    fi
    docker rm -f aea_smart_gateway >/dev/null 2>&1
    rm -rf "$DATA_DIR"
    rm -f "$INFO_FILE"
    rm -f /usr/local/bin/aea_gateway
    echo "[AEA] Module successfully removed."
    exit 0
fi

echo "[AEA] Initializing Smart Gateway module..."
INBOUND_PORT=$BASE_INBOUND_PORT

# Проверяем, свободен ли порт. Если занят, берем следующий десяток.
while ss -tuln | grep -q ":$INBOUND_PORT " || netstat -tuln | grep -q ":$INBOUND_PORT "; do
    INBOUND_PORT=$((INBOUND_PORT + 10))
done

if ! command -v docker >/dev/null 2>&1 || ! command -v jq >/dev/null 2>&1; then
    export DEBIAN_FRONTEND=noninteractive
    apt-get update -yq >/dev/null 2>&1
    apt-get install -yq docker.io jq curl wget >/dev/null 2>&1
    systemctl enable --now docker >/dev/null 2>&1
fi

mkdir -p "$DATA_DIR"
ADMIN_UUID=$(cat /proc/sys/kernel/random/uuid)

TARGET_ZONE="$BYPASS_ZONE"
if [ "$TARGET_ZONE" == "auto" ] || [ -z "$TARGET_ZONE" ]; then
    echo "[AEA] Detecting server country location automatically..."
    DETECTED_CC=$(curl -s --max-time 5 https://ipapi.co/country/ | tr '[:upper:]' '[:lower:]')
    if [ -n "$DETECTED_CC" ] && [ ${#DETECTED_CC} -eq 2 ]; then
        TARGET_ZONE="$DETECTED_CC"
        echo "[AEA] Auto-detected country zone: $TARGET_ZONE"
    else
        TARGET_ZONE="ru"
        echo "[AEA] Auto-detection failed. Falling back to default: ru"
    fi
fi

rm -f "$DATA_DIR"/*.srs

echo "[AEA] Fetching valid MetaCubeX GeoIP rule-set for zone: $TARGET_ZONE..."
curl -Lo "$DATA_DIR/geoip-${TARGET_ZONE}.srs" "https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geoip/${TARGET_ZONE}.srs"

if [ ! -s "$DATA_DIR/geoip-${TARGET_ZONE}.srs" ]; then
    echo "[AEA] Warning: Ruleset for $TARGET_ZONE not found, using generic bypass."
    curl -Lo "$DATA_DIR/geoip-${TARGET_ZONE}.srs" "https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geoip/private.srs"
fi

ROUTE_RULES=$(generate_route_rules "$GATEWAY_MODE" "$TARGET_ZONE")

# 3. ДОБАВЛЕНО ЯВНОЕ РАЗРЕШЕНИЕ UDP В КОНФИГЕ
echo "[AEA] Building core configuration..."
cat <<EOF > "$DATA_DIR/config.json"
{
  "log": { "level": "warn" },
  "dns": {
    "servers": [ { "tag": "dns-remote", "type": "local" } ],
    "final": "dns-remote",
    "strategy": "ipv4_only"
  },
  "inbounds": [
    {
      "type": "vless",
      "tag": "inbound-vless",
      "listen": "0.0.0.0",
      "listen_port": $INBOUND_PORT,
      "users": [ { "uuid": "$ADMIN_UUID", "flow": "xtls-rprx-vision" } ],
      "tls": {
        "enabled": true,
        "server_name": "vk.com",
        "reality": {
          "enabled": true,
          "handshake": { "server": "vk.com", "server_port": 443 },
          "private_key": "",
          "short_id": []
        }
      }
    }
  ],
  "outbounds": [
    { "type": "direct", "tag": "direct-out" },
    {
      "type": "vless",
      "tag": "tunnel-next-hop",
      "server": "$NEXT_HOP_IP",
      "server_port": $NEXT_HOP_PORT,
      "uuid": "$NEXT_HOP_UUID",
      "tls": {
        "enabled": true,
        "server_name": "$NEXT_HOP_SNI",
        "utls": { "enabled": true, "fingerprint": "chrome" }
      }
    }
  ],
  "route": {
    "rule_set": [
      { "tag": "geoip-${TARGET_ZONE}", "type": "local", "format": "binary", "path": "/etc/sing-box/geoip-${TARGET_ZONE}.srs" }
    ],
    "default_domain_resolver": "dns-remote",
    "rules": $ROUTE_RULES
  }
}
EOF

# Генерируем уникальные ЛОКАЛЬНЫЕ ключи для самого домашнего шлюза
REALITY_KEYS=$(docker run --rm ghcr.io/sagernet/sing-box:latest generate reality-keypair)
LOCAL_PRIVATE_KEY=$(echo "$REALITY_KEYS" | grep "PrivateKey" | awk '{print $2}')
LOCAL_PUBLIC_KEY=$(echo "$REALITY_KEYS" | grep "PublicKey" | awk '{print $2}')
LOCAL_SHORT_ID=$(cat /dev/urandom | tr -dc 'a-f0-9' | fold -w 16 | head -n 1)

# 1. Записываем локальные ключи во входящее подключение (чтобы шлюз мог принимать вас)
jq --arg pk "$LOCAL_PRIVATE_KEY" --arg sid "$LOCAL_SHORT_ID" '.inbounds[0].tls.reality.private_key = $pk | .inbounds[0].tls.reality.short_id = [$sid]' "$DATA_DIR/config.json" > "$DATA_DIR/tmp.json" && mv "$DATA_DIR/tmp.json" "$DATA_DIR/config.json"

# 2. Если мы ретранслятор (Relay), записываем ключи от VPS в исходящее подключение (чтобы шлюз мог отдавать трафик дальше)
if [ "$GATEWAY_MODE" = "to_vpn" ] && [ -n "$NEXT_HOP_PBK" ] && [[ "$NEXT_HOP_PBK" != "{{"* ]]; then
    jq --arg pbk "$NEXT_HOP_PBK" --arg sid "$NEXT_HOP_SID" '.outbounds[1].tls += {"reality": {"enabled": true, "public_key": $pbk, "short_id": $sid}}' "$DATA_DIR/config.json" > "$DATA_DIR/tmp.json" && mv "$DATA_DIR/tmp.json" "$DATA_DIR/config.json"
fi

# 3. РАЗРЕШАЕМ UDP В UFW
if command -v ufw >/dev/null 2>&1; then
    ufw allow "$INBOUND_PORT"/tcp >/dev/null 2>&1
    ufw allow "$INBOUND_PORT"/udp >/dev/null 2>&1
fi

docker rm -f aea_smart_gateway >/dev/null 2>&1
docker run -d --name aea_smart_gateway --restart unless-stopped --network host -v "$DATA_DIR":/etc/sing-box ghcr.io/sagernet/sing-box:latest run -c /etc/sing-box/config.json >/dev/null 2>&1

# КРИТИЧЕСКИ ВАЖНО: Отдаем Android-приложению ЛОКАЛЬНЫЕ ключи шлюза!
JSON_DATA="{\"status\": \"success\", \"inbound_port\": $INBOUND_PORT, \"admin_uuid\": \"$ADMIN_UUID\", \"public_key\": \"$LOCAL_PUBLIC_KEY\", \"short_id\": \"$LOCAL_SHORT_ID\", \"mode\": \"$GATEWAY_MODE\", \"bypass_zone\": \"$TARGET_ZONE\"}"
echo "$JSON_DATA" | base64 > "$INFO_FILE"
chmod 600 "$INFO_FILE"

MODULE_PATH="/usr/local/bin/aea_gateway"
cat "$0" > "$MODULE_PATH"
chmod +x "$MODULE_PATH"

exit 0
