#!/usr/bin/env bash
# Nexus — MySQL dump（Docker 1Panel / 宿主机 mysqldump 通用）
#
#   bash deploy/mysql_dump_to_file.sh --output /path/dump.sql [--root /opt/nexus]
#   bash deploy/mysql_dump_to_file.sh --output /path/dump.sql --db-url 'mysql+aiomysql://...'
#
# 策略（按序）:
#   1. DB host 为运行中容器名 → docker exec 该容器内 mysqldump（连 127.0.0.1）
#   2. 宿主机有 mysqldump 且 host 可解析 → 本机 mysqldump
#   3. 1panel-network 存在 → docker run --rm mysql:8 客户端
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
NEXUS_ROOT="${NEXUS_ROOT:-/opt/nexus}"
OUTPUT=""
DB_URL=""

usage() {
    cat <<'EOF'
用法: mysql_dump_to_file.sh --output FILE.sql [--root /opt/nexus] [--db-url URL]
EOF
}

while [[ $# -gt 0 ]]; do
    case "$1" in
        --output|-o) OUTPUT="$2"; shift 2 ;;
        --root) NEXUS_ROOT="$2"; shift 2 ;;
        --db-url) DB_URL="$2"; shift 2 ;;
        -h|--help) usage; exit 0 ;;
        *) echo "未知参数: $1" >&2; usage; exit 1 ;;
    esac
done

if [[ -z "$OUTPUT" ]]; then
    echo "缺少 --output" >&2
    usage
    exit 1
fi

resolve_db_url() {
    if [[ -n "$DB_URL" ]]; then
        echo "$DB_URL"
        return 0
    fi
    local cname url
    cname="$(docker ps --format '{{.Names}}' 2>/dev/null | grep -E 'nexus-prod-nexus|nexus-nexus-1' | head -1 || true)"
    if [[ -n "$cname" ]]; then
        url="$(docker exec "$cname" grep -E '^NEXUS_DATABASE_URL=' /app/.env 2>/dev/null | head -1 | cut -d= -f2- | tr -d '"' | tr -d "'" || true)"
        [[ -n "$url" ]] && echo "$url" && return 0
    fi
    for f in \
        "${NEXUS_ROOT}/docker/.env.prod" \
        "${NEXUS_ROOT}/.env" \
        ; do
        [[ -f "$f" ]] || continue
        url="$(grep -E '^NEXUS_DATABASE_URL=' "$f" 2>/dev/null | head -1 | cut -d= -f2- | tr -d '"' | tr -d "'" || true)"
        [[ -n "$url" ]] && echo "$url" && return 0
    done
    return 1
}

DB_URL="$(resolve_db_url || true)"
if [[ -z "$DB_URL" ]]; then
    echo "未找到 NEXUS_DATABASE_URL" >&2
    exit 1
fi

python3 - "$DB_URL" "$OUTPUT" <<'PY'
import shutil
import subprocess
import sys
import urllib.parse


def docker_names() -> set[str]:
    r = subprocess.run(
        ["docker", "ps", "--format", "{{.Names}}"],
        capture_output=True,
        text=True,
        check=False,
    )
    return {ln.strip() for ln in (r.stdout or "").splitlines() if ln.strip()}


def network_exists(name: str) -> bool:
    return (
        subprocess.run(
            ["docker", "network", "inspect", name],
            capture_output=True,
            check=False,
        ).returncode
        == 0
    )


def write_dump(cmd: list[str], env: dict[str, str], out: str) -> int:
    r = subprocess.run(cmd, env=env, capture_output=True, text=True)
    if r.returncode != 0:
        sys.stderr.write(r.stderr or r.stdout or "mysqldump failed\n")
        return r.returncode
    with open(out, "w", encoding="utf-8") as fh:
        fh.write(r.stdout)
    return 0


def dump_flags(db: str) -> list[str]:
    return [
        "--single-transaction",
        "--routines",
        "--triggers",
        "--set-gtid-purged=OFF",
        db,
    ]


url = sys.argv[1].replace("mysql+aiomysql://", "mysql://", 1)
url = url.replace("mysql+asyncmy://", "mysql://", 1)
out = sys.argv[2]
p = urllib.parse.urlparse(url)
user = urllib.parse.unquote(p.username or "")
password = urllib.parse.unquote(p.password or "")
host = p.hostname or "127.0.0.1"
if host == "host.docker.internal":
    host = "127.0.0.1"
port = str(p.port or 3306)
db = (p.path or "/nexus").lstrip("/").split("?")[0]
env = {**__import__("os").environ, "MYSQL_PWD": password}
names = docker_names()

# 1) MySQL 跑在 Docker 容器内（1Panel 常见：URL host = 容器名）
if host in names:
    cmd = [
        "docker",
        "exec",
        "-e",
        f"MYSQL_PWD={password}",
        host,
        "mysqldump",
        "-h",
        "127.0.0.1",
        "-P",
        port,
        "-u",
        user,
        *dump_flags(db),
    ]
    rc = write_dump(cmd, env, out)
    if rc == 0:
        sys.exit(0)
    sys.stderr.write(f"docker exec {host} mysqldump 失败，尝试其它方式…\n")

# 2) 宿主机 mysqldump
if shutil.which("mysqldump"):
    cmd = [
        "mysqldump",
        "-h",
        host,
        "-P",
        port,
        "-u",
        user,
        *dump_flags(db),
    ]
    rc = write_dump(cmd, env, out)
    if rc == 0:
        sys.exit(0)

# 3) 临时 mysql 客户端容器（1panel-network）
for net in ("1panel-network", "bridge"):
    if not network_exists(net):
        continue
    cmd = [
        "docker",
        "run",
        "--rm",
        "--network",
        net,
        "-e",
        f"MYSQL_PWD={password}",
        "mysql:8.0",
        "mysqldump",
        "-h",
        host,
        "-P",
        port,
        "-u",
        user,
        *dump_flags(db),
    ]
    rc = write_dump(cmd, env, out)
    if rc == 0:
        sys.exit(0)

sys.stderr.write("所有 mysqldump 策略均失败（无宿主机客户端且 Docker 回退不可用）\n")
sys.exit(1)
PY
