#!/bin/bash
# ═══════════════════════════════════════════════════════════
#  Hysteria 2 — установка клиентского конфига
#
#  - Пишет native-конфиг Hysteria (config.yaml)
#  - Если уже стоит Xray — добавляет outbound JSON и печатает
#    его в терминал (бинарь Hysteria не трогает)
#  - Всегда печатает ссылку и пути к файлам
#
#  Использование:
#    bash install-hysteria-config.sh 'hysteria2://…'
#    curl -sL https://ai.arckep.ru/install-hysteria-config.sh | bash -s -- 'hysteria2://…'
#
#  Опции:
#    --uri URI         ссылка (то же, что позиционный аргумент)
#    --dir DIR         каталог (по умолчанию: ~/.config/hysteria)
#    --name NAME       имя профиля / tag outbound (из #fragment ссылки)
#    --socks PORT      SOCKS5 (default 1080)
#    --http PORT       HTTP-прокси (default 8080)
#    --no-install      не ставить бинарь Hysteria
#    --force-hysteria  ставить/искать Hysteria даже если есть Xray
#    --start           запустить native-клиент (foreground)
# ═══════════════════════════════════════════════════════════
set -euo pipefail

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

URI=""
CONFIG_DIR="${HOME}/.config/hysteria"
PROFILE_NAME=""
SOCKS_PORT="1080"
HTTP_PORT="8080"
NO_INSTALL=false
FORCE_HYSTERIA=false
DO_START=false

while [[ $# -gt 0 ]]; do
    case $1 in
        --uri) URI="$2"; shift 2 ;;
        --dir) CONFIG_DIR="$2"; shift 2 ;;
        --name) PROFILE_NAME="$2"; shift 2 ;;
        --socks) SOCKS_PORT="$2"; shift 2 ;;
        --http) HTTP_PORT="$2"; shift 2 ;;
        --no-install) NO_INSTALL=true; shift ;;
        --force-hysteria) FORCE_HYSTERIA=true; shift ;;
        --start) DO_START=true; shift ;;
        -h|--help)
            sed -n '2,24p' "$0" | sed 's/^# \?//'
            exit 0
            ;;
        hysteria2://*|hy2://*)
            URI="$1"; shift
            ;;
        *)
            echo -e "${RED}Неизвестный параметр: $1${NC}"
            echo "Пример: bash install-hysteria-config.sh 'hysteria2://pass@1.2.3.4:443/?insecure=1&sni=www.bing.com'"
            exit 1
            ;;
    esac
done

if [[ -z "$URI" ]]; then
    echo -e "${RED}Нужна ссылка hysteria2://…${NC}"
    echo ""
    echo "  bash install-hysteria-config.sh 'hysteria2://…'"
    echo "  curl -sL https://ai.arckep.ru/install-hysteria-config.sh | bash -s -- 'hysteria2://…'"
    exit 1
fi

case "$URI" in
    hy2://*) URI="hysteria2://${URI#hy2://}" ;;
    hysteria2://*) ;;
    *)
        echo -e "${RED}Ссылка должна начинаться с hysteria2:// или hy2://${NC}"
        exit 1
        ;;
esac

# ── python3 ──
if ! command -v python3 &>/dev/null; then
    if [[ $EUID -eq 0 ]]; then
        export DEBIAN_FRONTEND=noninteractive
        apt-get update -qq >/dev/null 2>&1 || true
        apt-get install -y -qq python3 >/dev/null 2>&1 || true
    fi
fi
if ! command -v python3 &>/dev/null; then
    echo -e "${RED}Нужен python3 для разбора ссылки${NC}"
    exit 1
fi

# ── Разбор URI ──
eval "$(python3 - "$URI" "${PROFILE_NAME}" <<'PY'
import sys, urllib.parse, shlex, re
raw = sys.argv[1]
forced_name = sys.argv[2] if len(sys.argv) > 2 else ""
u = urllib.parse.urlparse(raw)
if u.scheme not in ("hysteria2", "hy2"):
    print("echo -e \"${RED}Неверная схема URI${NC}\"; exit 1"); sys.exit(0)
qs = urllib.parse.parse_qs(u.query)
host = u.hostname or ""
port = u.port or 443
auth = urllib.parse.unquote(u.username or "")
if u.password:
    auth = f"{auth}:{urllib.parse.unquote(u.password)}"
sni = (qs.get("sni") or [""])[0]
insecure = (qs.get("insecure") or ["0"])[0] in ("1", "true", "True")
obfs = (qs.get("obfs") or [""])[0]
obfs_pass = (qs.get("obfs-password") or [""])[0]
pin = (qs.get("pinSHA256") or qs.get("pinsha256") or [""])[0]
name = forced_name or urllib.parse.unquote(u.fragment or "") or "hysteria2"
# safe filename / xray tag
safe = re.sub(r"[^A-Za-z0-9._-]+", "-", name).strip("-") or "hysteria2"
if not host or not auth:
    print("echo -e \"${RED}В ссылке нет хоста или пароля${NC}\"; exit 1"); sys.exit(0)
def exp(k, v):
    print(f"{k}={shlex.quote(str(v))}")
exp("P_HOST", host)
exp("P_PORT", port)
exp("P_AUTH", auth)
exp("P_SNI", sni)
exp("P_INSECURE", "1" if insecure else "0")
exp("P_OBFS", obfs)
exp("P_OBFS_PASS", obfs_pass)
exp("P_PIN", pin)
exp("P_NAME", name)
exp("P_SAFE", safe)
PY
)"

# ── Поиск Xray ──
find_xray() {
    if command -v xray &>/dev/null; then
        command -v xray
        return 0
    fi
    local c
    for c in \
        /usr/local/bin/xray \
        /usr/bin/xray \
        /usr/local/x-ui/bin/xray-linux-amd64 \
        /usr/local/x-ui/bin/xray-linux-arm64
    do
        if [[ -x "$c" ]]; then
            echo "$c"
            return 0
        fi
    done
    # any xray-linux-* under 3x-ui
    local found
    found=$(find /usr/local/x-ui/bin -name 'xray-linux-*' -type f -executable 2>/dev/null | head -1 || true)
    if [[ -n "$found" ]]; then
        echo "$found"
        return 0
    fi
    return 1
}

XRAY_BIN=""
HAS_XRAY=false
if XRAY_BIN=$(find_xray); then
    HAS_XRAY=true
fi

HAS_HYSTERIA=false
if command -v hysteria &>/dev/null; then
    HAS_HYSTERIA=true
fi

echo -e "${CYAN}╔═══════════════════════════════════════════╗${NC}"
echo -e "${CYAN}║  Hysteria 2 — клиентский конфиг           ║${NC}"
echo -e "${CYAN}╠═══════════════════════════════════════════╣${NC}"
echo -e "${CYAN}║  Сервер:  ${GREEN}${P_HOST}:${P_PORT}${NC}"
echo -e "${CYAN}║  Профиль: ${GREEN}${P_NAME}${NC}"
echo -e "${CYAN}║  Каталог: ${GREEN}${CONFIG_DIR}${NC}"
if [[ "$HAS_XRAY" == true ]]; then
echo -e "${CYAN}║  Xray:    ${GREEN}найден${NC} (${XRAY_BIN})"
else
echo -e "${CYAN}║  Xray:    ${YELLOW}не найден${NC}"
fi
if [[ "$HAS_HYSTERIA" == true ]]; then
echo -e "${CYAN}║  Hysteria:${GREEN} найден${NC} ($(command -v hysteria))"
else
echo -e "${CYAN}║  Hysteria:${YELLOW} не найден${NC}"
fi
echo -e "${CYAN}╚═══════════════════════════════════════════╝${NC}"

mkdir -p "$CONFIG_DIR"

# Имена файлов профиля (не затираем чужие — новый файл на каждый профиль)
HY_CFG="${CONFIG_DIR}/config-${P_SAFE}.yaml"
HY_CFG_DEFAULT="${CONFIG_DIR}/config.yaml"
URI_FILE="${CONFIG_DIR}/share-${P_SAFE}.uri"
EXPANDED="${CONFIG_DIR}/config-${P_SAFE}.expanded.yaml"
XRAY_OUT="${CONFIG_DIR}/xray-outbound-${P_SAFE}.json"
XRAY_SNIPPET="${CONFIG_DIR}/xray-outbound-${P_SAFE}.snippet.json"

# ── Native Hysteria config ──
python3 - "$URI" "$P_NAME" "$P_HOST" "$P_PORT" "$SOCKS_PORT" "$HTTP_PORT" "$HY_CFG" <<'PY'
import json, sys, datetime
uri, name, host, port, socks, http, path = sys.argv[1:8]
doc = f"""# Generated by install-hysteria-config.sh — {datetime.datetime.now():%Y-%m-%d %H:%M}
# Profile: {name}
# Server:  {host}:{port}

server: {json.dumps(uri)}

bandwidth:
  up: 50 mbps
  down: 200 mbps

socks5:
  listen: 127.0.0.1:{socks}

http:
  listen: 127.0.0.1:{http}
"""
open(path, "w", encoding="utf-8").write(doc)
PY

# expanded human view
{
    echo "# Expanded view (reference). Active: $(basename "$HY_CFG")"
    echo "server: ${P_HOST}:${P_PORT}"
    echo "auth: ${P_AUTH}"
    echo "tls:"
    [[ -n "$P_SNI" ]] && echo "  sni: ${P_SNI}"
    [[ "$P_INSECURE" == "1" ]] && echo "  insecure: true"
    [[ -n "$P_PIN" ]] && echo "  pinSHA256: ${P_PIN}"
    if [[ -n "$P_OBFS" ]]; then
        echo "obfs:"
        echo "  type: ${P_OBFS}"
        if [[ -n "$P_OBFS_PASS" ]]; then
            echo "  ${P_OBFS}:"
            echo "    password: ${P_OBFS_PASS}"
        fi
    fi
    echo "socks5:"
    echo "  listen: 127.0.0.1:${SOCKS_PORT}"
    echo "http:"
    echo "  listen: 127.0.0.1:${HTTP_PORT}"
} > "$EXPANDED"

printf '%s\n' "$URI" > "$URI_FILE"

# default symlink/copy for plain `hysteria` without -c
cp -f "$HY_CFG" "$HY_CFG_DEFAULT"
chmod 600 "$HY_CFG" "$HY_CFG_DEFAULT" "$EXPANDED" "$URI_FILE" 2>/dev/null || true

# ── Xray outbound (если Xray есть — основной сценарий «уже стоит») ──
if [[ "$HAS_XRAY" == true ]]; then
    python3 - "$P_SAFE" "$P_HOST" "$P_PORT" "$P_AUTH" "$P_SNI" "$P_INSECURE" "$P_OBFS" "$P_OBFS_PASS" "$P_PIN" "$XRAY_OUT" "$XRAY_SNIPPET" <<'PY'
import json, sys
tag, host, port, auth, sni, insecure, obfs, obfs_pass, pin, path_full, path_snip = sys.argv[1:12]
port = int(port)
insecure = insecure in ("1", "true", "True")

hysteria_settings = {
    "version": 2,
    "auth": auth,
    "up": "50mbps",
    "down": "200mbps",
    "udpIdleTimeout": 120,
}
if obfs:
    # Xray salamander field names vary by version; keep both common forms
    hysteria_settings["obfs"] = {
        "type": obfs,
        "password": obfs_pass or "",
        "salamanderPassword": obfs_pass or "",
    }

tls = {
    "serverName": sni or host,
    "allowInsecure": insecure,
    "alpn": ["h3"],
}
if pin:
    tls["pinnedPeerCertSha256"] = pin

outbound = {
    "tag": f"hy2-{tag}",
    "protocol": "hysteria",
    "settings": {
        "version": 2,
        "address": host,
        "port": port,
    },
    "streamSettings": {
        "network": "hysteria",
        "security": "tls",
        "tlsSettings": tls,
        "hysteriaSettings": hysteria_settings,
    },
}

# Full minimal config (standalone run: xray run -c file)
full = {
    "log": {"loglevel": "warning"},
    "inbounds": [
        {
            "tag": "socks-in",
            "listen": "127.0.0.1",
            "port": 1080,
            "protocol": "socks",
            "settings": {"udp": True},
        },
        {
            "tag": "http-in",
            "listen": "127.0.0.1",
            "port": 8080,
            "protocol": "http",
        },
    ],
    "outbounds": [
        outbound,
        {"tag": "direct", "protocol": "freedom"},
        {"tag": "block", "protocol": "blackhole"},
    ],
    "routing": {
        "domainStrategy": "AsIs",
        "rules": [
            {"type": "field", "outboundTag": f"hy2-{tag}", "network": "tcp,udp"}
        ],
    },
}

open(path_full, "w", encoding="utf-8").write(json.dumps(full, ensure_ascii=False, indent=2) + "\n")
open(path_snip, "w", encoding="utf-8").write(json.dumps(outbound, ensure_ascii=False, indent=2) + "\n")
PY
    chmod 600 "$XRAY_OUT" "$XRAY_SNIPPET" 2>/dev/null || true

    # Аккуратно добавить outbound в существующий config.json Xray (writable)
    CANDIDATE_CONFIGS=(
        "${HOME}/.config/xray/config.json"
        "${HOME}/xray/config.json"
        "/usr/local/etc/xray/config.json"
        "/etc/xray/config.json"
        "/usr/local/x-ui/bin/config.json"
    )
    MERGED=""
    for cfg in "${CANDIDATE_CONFIGS[@]}"; do
        [[ -f "$cfg" && -w "$cfg" ]] || continue
        merge_result=$(python3 - "$cfg" "$XRAY_SNIPPET" <<'PY'
import json, sys, shutil, time
cfg_path, snip_path = sys.argv[1], sys.argv[2]
try:
    with open(cfg_path, encoding="utf-8") as f:
        data = json.load(f)
    with open(snip_path, encoding="utf-8") as f:
        outbound = json.load(f)
except Exception as e:
    print(f"skip:{e}")
    sys.exit(0)
outs = data.get("outbounds")
if not isinstance(outs, list):
    print("skip:no-outbounds")
    sys.exit(0)
tag = outbound.get("tag")
if any(isinstance(o, dict) and o.get("tag") == tag for o in outs):
    data["outbounds"] = [
        outbound if (isinstance(o, dict) and o.get("tag") == tag) else o for o in outs
    ]
    action = "replaced"
else:
    insert_at = len(outs)
    for i, o in enumerate(outs):
        if isinstance(o, dict) and o.get("protocol") in ("freedom", "blackhole"):
            insert_at = i
            break
    outs.insert(insert_at, outbound)
    data["outbounds"] = outs
    action = "added"
bak = cfg_path + ".bak." + time.strftime("%Y%m%d%H%M%S")
shutil.copy2(cfg_path, bak)
with open(cfg_path, "w", encoding="utf-8") as f:
    json.dump(data, f, ensure_ascii=False, indent=2)
    f.write("\n")
print(f"ok:{action}:{cfg_path} (backup {bak})")
PY
)
        if [[ "$merge_result" == ok:* ]]; then
            MERGED="$merge_result"
            break
        fi
    done
fi

# ── Бинарь Hysteria: не ставим, если Xray уже есть (если не --force-hysteria) ──
ensure_hysteria() {
    if [[ "$HAS_HYSTERIA" == true ]]; then
        echo -e "  Бинарь hysteria ${GREEN}уже есть${NC}: $(command -v hysteria)"
        return 0
    fi
    if [[ "$NO_INSTALL" == true ]]; then
        echo -e "  ${YELLOW}--no-install: бинарь не ставим${NC}"
        return 0
    fi
    if [[ "$HAS_XRAY" == true && "$FORCE_HYSTERIA" != true ]]; then
        echo -e "  Xray уже стоит — ${GREEN}бинарь Hysteria не ставим${NC}"
        echo -e "  (нужен native Hysteria → перезапустите с ${BOLD}--force-hysteria${NC})"
        return 0
    fi
    echo -e "  Установка Hysteria 2…"
    if [[ $EUID -eq 0 ]]; then
        curl -fsSL https://get.hy2.sh/ | bash
    elif command -v sudo &>/dev/null; then
        curl -fsSL https://get.hy2.sh/ | sudo bash
    else
        echo -e "  ${YELLOW}Нет root/sudo — качаю бинарь в ~/.local/bin${NC}"
        mkdir -p "${HOME}/.local/bin"
        local arch os url
        arch=$(uname -m)
        case "$arch" in
            x86_64|amd64) arch="amd64" ;;
            aarch64|arm64) arch="arm64" ;;
            *)
                echo -e "${RED}Неизвестная архитектура: $arch${NC}"
                return 1
                ;;
        esac
        os=$(uname -s | tr '[:upper:]' '[:lower:]')
        url=$(curl -fsSL "https://api.github.com/repos/apernet/hysteria/releases/latest" \
            | python3 -c "import sys,json,re; j=json.load(sys.stdin); arch=sys.argv[1]; osn=sys.argv[2];
assets=j.get('assets') or [];
pat=re.compile(rf'hysteria-{osn}-{arch}(\.exe)?$', re.I);
cands=[a for a in assets if pat.search(a['name']) and 'avx' not in a['name'].lower() and 'fips' not in a['name'].lower()]
if not cands:
  cands=[a for a in assets if arch in a['name'] and osn in a['name']]
print(cands[0]['browser_download_url'] if cands else '')" "$arch" "$os")
        if [[ -z "$url" ]]; then
            echo -e "${RED}Не удалось найти релиз${NC}"
            return 1
        fi
        curl -fsSL "$url" -o "${HOME}/.local/bin/hysteria"
        chmod +x "${HOME}/.local/bin/hysteria"
        export PATH="${HOME}/.local/bin:${PATH}"
        echo -e "  Установлен в ${GREEN}~/.local/bin/hysteria${NC}"
    fi
    if command -v hysteria &>/dev/null; then
        HAS_HYSTERIA=true
        echo -e "  Бинарь ${GREEN}готов${NC}: $(command -v hysteria)"
    fi
}

echo ""
echo -e "${GREEN}[1/2]${NC} Конфиги…"
echo -e "  Hysteria: ${GREEN}${HY_CFG}${NC}"
if [[ "$HAS_XRAY" == true ]]; then
    echo -e "  Xray full: ${GREEN}${XRAY_OUT}${NC}"
    echo -e "  Xray snip: ${GREEN}${XRAY_SNIPPET}${NC}"
    if [[ -n "${MERGED:-}" ]]; then
        echo -e "  В существующий config.json: ${GREEN}${MERGED#ok:}${NC}"
    else
        echo -e "  ${YELLOW}Живой config.json Xray не трогали${NC} (нет writable / уже ок)"
        echo -e "  Вставьте snippet в outbounds вручную или:"
        echo -e "  ${BOLD}xray run -c ${XRAY_OUT}${NC}"
    fi
fi

echo ""
echo -e "${GREEN}[2/2]${NC} Бинарь…"
ensure_hysteria

# ── Вывод в терминал ──
echo ""
echo -e "${CYAN}═══════════════════════════════════════════${NC}"
echo -e "${CYAN}  ${BOLD}ССЫЛКА (для Hiddify / NekoBox / буфер)${NC}"
echo -e "${CYAN}═══════════════════════════════════════════${NC}"
echo -e "  ${GREEN}${URI}${NC}"
echo ""

if [[ "$HAS_XRAY" == true ]]; then
    echo -e "${CYAN}═══════════════════════════════════════════${NC}"
    echo -e "${CYAN}  ${BOLD}XRAY OUTBOUND (добавлен / для вставки)${NC}"
    echo -e "${CYAN}═══════════════════════════════════════════${NC}"
    cat "$XRAY_SNIPPET"
    echo ""
    echo -e "  Полный минимальный конфиг Xray:"
    echo -e "  ${BOLD}${XRAY_OUT}${NC}"
    echo -e "  Запуск: ${BOLD}\"${XRAY_BIN}\" run -c ${XRAY_OUT}${NC}"
    echo ""
fi

echo -e "${CYAN}═══════════════════════════════════════════${NC}"
echo -e "${CYAN}  ${BOLD}NATIVE HYSTERIA${NC}"
echo -e "${CYAN}═══════════════════════════════════════════${NC}"
echo -e "  Конфиг: ${BOLD}${HY_CFG}${NC}"
echo -e "  (также скопирован в ${HY_CFG_DEFAULT})"
if command -v hysteria &>/dev/null; then
    echo -e "  Запуск: ${BOLD}hysteria -c ${HY_CFG}${NC}"
else
    echo -e "  ${YELLOW}Бинарь hysteria не установлен${NC} — для GUI хватит ссылки выше"
fi
echo ""
echo -e "  SOCKS5: ${GREEN}127.0.0.1:${SOCKS_PORT}${NC}   HTTP: ${GREEN}127.0.0.1:${HTTP_PORT}${NC}"
echo ""
echo -e "${GREEN}Готово. Новый профиль «${P_NAME}» добавлен, старые файлы не удалялись.${NC}"
echo ""

if [[ "$DO_START" == true ]]; then
    if command -v hysteria &>/dev/null; then
        echo -e "${GREEN}Запуск native-клиента…${NC} (Ctrl+C — стоп)"
        exec hysteria -c "$HY_CFG"
    elif [[ "$HAS_XRAY" == true ]]; then
        echo -e "${GREEN}Запуск Xray…${NC} (Ctrl+C — стоп)"
        exec "$XRAY_BIN" run -c "$XRAY_OUT"
    else
        echo -e "${RED}Нечего запускать: нет hysteria и xray${NC}"
        exit 1
    fi
fi
