#!/usr/bin/env bash
#
# install-docker.sh
# 零刻 ME Pro 龙芯（Loongnix 25 / loongarch64）Docker 安装脚本
#
# 用法
#   sudo bash install-docker.sh
#   sudo bash install-docker.sh --no-mirror      不配置镜像加速
#   sudo bash install-docker.sh --skip-test      跳过测试容器
#   sudo bash install-docker.sh --user zhangsan  指定加入 docker 组的用户
#
set -euo pipefail

SCRIPT_VERSION="1.0"

ORIG_ARGS=("$@")

USE_MIRROR=1
SKIP_TEST=0
FORCE=0
WANT_USER=""

while [ $# -gt 0 ]; do
    case "$1" in
        --no-mirror) USE_MIRROR=0 ;;
        --skip-test) SKIP_TEST=1 ;;
        --force)     FORCE=1 ;;
        --user)      shift; WANT_USER="${1:-}" ;;
        -h|--help)
            sed -n '3,10p' "$0" | sed 's/^# \{0,1\}//'
            exit 0 ;;
        *)
            printf '未知参数 %s，执行 -h 查看用法。\n' "$1"
            exit 2 ;;
    esac
    shift
done

# ---------- 获取 root 权限 ----------
if [ "$(id -u)" -ne 0 ]; then
    printf '本脚本需要修改系统配置，正在请求 root 权限。\n'
    exec sudo -E bash "$0" "${ORIG_ARGS[@]}"
fi

# ---------- 输出样式 ----------
if [ -t 1 ]; then
    C_T=$'\033[1;36m'; C_OK=$'\033[32m'; C_W=$'\033[33m'; C_E=$'\033[31m'; C_D=$'\033[2m'; C_0=$'\033[0m'
else
    C_T=""; C_OK=""; C_W=""; C_E=""; C_D=""; C_0=""
fi

step() { printf '\n%s%s%s  %s\n' "$C_T" "$1" "$C_0" "$2"; }
ok()   { printf '    %s%s%s\n' "$C_OK" "$*" "$C_0"; }
note() { printf '    %s%s%s\n' "$C_D" "$*" "$C_0"; }
warn() { printf '    %s%s%s\n' "$C_W" "$*" "$C_0"; }
die()  { printf '\n%s安装中止。%s %s\n' "$C_E" "$C_0" "$*"; exit 1; }

printf '\n%s零刻 ME Pro 龙芯 Docker 安装脚本 v%s%s\n' "$C_T" "$SCRIPT_VERSION" "$C_0"
note "适用机型 ME Pro 龙芯　系统 Loongnix 25　架构 loongarch64"
note "安装内容 docker.io、containerd、docker compose"

# ---------- 1 系统环境 ----------
step "1/8" "检查系统环境"

ARCH="$(uname -m)"
PRETTY="未知系统"
if [ -r /etc/os-release ]; then
    # shellcheck disable=SC1091
    . /etc/os-release
    PRETTY="${PRETTY_NAME:-$PRETTY}"
fi

note "系统 $PRETTY"
note "架构 $ARCH"

case "$ARCH" in
    loongarch64|loong64)
        ok "架构校验通过"
        ;;
    *)
        warn "当前架构为 $ARCH，非 loongarch64"
        if [ "$FORCE" -eq 0 ]; then
            die "非龙芯平台建议使用 Docker 官方仓库，如需继续请加 --force 参数。"
        fi
        ;;
esac

if ! command -v apt-get >/dev/null 2>&1; then
    die "未找到 apt-get，本脚本仅适用于 Debian 系系统。"
fi

if command -v docker >/dev/null 2>&1; then
    note "检测到已安装 Docker $(docker --version 2>/dev/null | sed -e 's/^Docker version //' -e 's/,.*//')"
    note "将执行安装校验与配置补齐，已安装的容器与镜像不受影响"
fi

# ---------- 2 更新软件源 ----------
step "2/8" "更新软件源"
note "执行 apt-get update，约需半分钟"

APTLOG="$(mktemp)"
if ! apt-get update -qq >"$APTLOG" 2>&1; then
    tail -n 12 "$APTLOG" | sed 's/^/      /'
    rm -f "$APTLOG"
    die "软件源更新失败，请检查网络连通性与 /etc/apt/sources.list 后重试。"
fi
rm -f "$APTLOG"
ok "软件源可用"

# ---------- 3 安装软件包 ----------
step "3/8" "安装 docker.io 与 docker-compose"

if fuser -s /var/lib/dpkg/lock-frontend 2>/dev/null; then
    warn "检测到其他 apt 进程正在运行，等待其结束"
    for _ in $(seq 1 40); do
        fuser -s /var/lib/dpkg/lock-frontend 2>/dev/null || break
        sleep 3
    done
    fuser -s /var/lib/dpkg/lock-frontend 2>/dev/null && die "等待超时，请关闭其他 apt 进程后重新执行。"
    ok "apt 锁已释放，继续安装"
fi

export DEBIAN_FRONTEND=noninteractive
note "正在安装 runc、containerd、docker-cli 等依赖，约需 1 至 2 分钟，请勿中断"

INSTLOG="$(mktemp)"
trap 'rm -f "$INSTLOG"' EXIT
if ! apt-get install -y -qq docker.io docker-compose >"$INSTLOG" 2>&1; then
    tail -n 15 "$INSTLOG" | sed 's/^/      /'
    die "软件包安装失败，请执行 apt-cache policy docker.io 确认软件源中是否包含该软件包。"
fi

DOCKER_PKG_VER="$(dpkg-query -W -f='${Version}' docker.io 2>/dev/null || echo 未知)"
COMPOSE_PKG_VER="$(dpkg-query -W -f='${Version}' docker-compose 2>/dev/null || echo 未知)"
ok "docker.io $DOCKER_PKG_VER 安装完成"
ok "docker-compose $COMPOSE_PKG_VER 安装完成"

# ---------- 4 守护进程配置 ----------
step "4/8" "配置守护进程"

mkdir -p /etc/docker
CONFIG_CHANGED=0
NEWJSON="$(mktemp)"

if [ "$USE_MIRROR" -eq 1 ]; then
    cat > "$NEWJSON" <<'JSON'
{
  "registry-mirrors": ["https://docker.m.daocloud.io", "https://docker.1ms.run"],
  "log-driver": "json-file",
  "log-opts": { "max-size": "50m", "max-file": "3" },
  "live-restore": true
}
JSON
    note "已配置镜像加速 docker.m.daocloud.io、docker.1ms.run"
else
    cat > "$NEWJSON" <<'JSON'
{
  "log-driver": "json-file",
  "log-opts": { "max-size": "50m", "max-file": "3" },
  "live-restore": true
}
JSON
    note "按参数要求未配置镜像加速"
fi

if [ -f /etc/docker/daemon.json ] && cmp -s "$NEWJSON" /etc/docker/daemon.json; then
    note "配置与当前一致，跳过写入"
    rm -f "$NEWJSON"
else
    if [ -f /etc/docker/daemon.json ]; then
        BACKUP="/etc/docker/daemon.json.bak.$(date +%Y%m%d%H%M%S)"
        cp -a /etc/docker/daemon.json "$BACKUP"
        note "原配置已备份至 $BACKUP"
    fi

    if dockerd --help 2>/dev/null | grep -q -- '--validate'; then
        if ! dockerd --validate --config-file="$NEWJSON" >/dev/null 2>&1; then
            rm -f "$NEWJSON"
            die "配置未通过语法校验，原文件未做改动。"
        fi
        ok "配置校验通过"
    fi

    mv "$NEWJSON" /etc/docker/daemon.json
    chmod 644 /etc/docker/daemon.json
    CONFIG_CHANGED=1
    ok "已写入 /etc/docker/daemon.json"
fi

note "日志上限 50MB 三份，避免容器日志占满存储"
note "已启用 live-restore，重启 docker 服务时容器不中断"

# ---------- 5 启动服务 ----------
step "5/8" "启动服务并设置开机自启"

systemctl enable docker >/dev/null 2>&1 || true
if systemctl is-active --quiet docker; then
    if [ "$CONFIG_CHANGED" -eq 1 ]; then
        systemctl restart docker
        ok "已按新配置重启 docker.service"
    else
        ok "配置未变更，docker.service 保持运行"
    fi
else
    systemctl start docker
    ok "docker.service 已启动"
fi

for _ in $(seq 1 20); do
    systemctl is-active --quiet docker && break
    sleep 1
done
systemctl is-active --quiet docker || die "docker.service 未能启动，请执行 journalctl -u docker -n 50 查看日志。"
ok "docker.service 运行中，已设置开机自启"

# ---------- 6 用户组 ----------
step "6/8" "添加用户到 docker 组"

TARGET_USER="$WANT_USER"
if [ -z "$TARGET_USER" ]; then
    TARGET_USER="${SUDO_USER:-}"
fi
if [ -z "$TARGET_USER" ] || [ "$TARGET_USER" = "root" ]; then
    TARGET_USER="$(logname 2>/dev/null || true)"
fi

if [ -z "$TARGET_USER" ] || [ "$TARGET_USER" = "root" ]; then
    warn "未识别到目标用户，本步骤跳过"
    note "如需指定用户，请使用 --user 参数重新执行"
else
    if id "$TARGET_USER" >/dev/null 2>&1; then
        usermod -aG docker "$TARGET_USER"
        ok "已将 $TARGET_USER 加入 docker 组"
        note "重新登录后生效，或执行 newgrp docker 立即生效"
    else
        warn "系统中不存在用户 $TARGET_USER，本步骤跳过"
    fi
fi

# ---------- 7 compose 插件 ----------
step "7/8" "注册 compose 插件"

if [ -x /usr/bin/docker-compose ]; then
    mkdir -p /usr/local/lib/docker/cli-plugins
    ln -sf /usr/bin/docker-compose /usr/local/lib/docker/cli-plugins/docker-compose
    if docker compose version >/dev/null 2>&1; then
        ok "docker compose $(docker compose version --short 2>/dev/null) 可用"
    else
        warn "插件链接已创建，重新登录后生效"
    fi
else
    warn "未找到 docker-compose，本步骤跳过"
fi

# ---------- 8 验证 ----------
step "8/8" "验证安装"

CLI_VER="$(docker version --format '{{.Client.Version}}' 2>/dev/null || true)"
SRV_VER="$(docker version --format '{{.Server.Version}}' 2>/dev/null || true)"
[ -n "$SRV_VER" ] || die "无法连接守护进程，请执行 systemctl status docker 查看服务状态。"

ok "客户端 $CLI_VER　服务端 $SRV_VER"
note "存储驱动 $(docker info --format '{{.Driver}}')　运行时 $(docker info --format '{{.DefaultRuntime}}')　Cgroup $(docker info --format '{{.CgroupDriver}}')"

if [ "$SKIP_TEST" -eq 0 ]; then
    TEST_IMG="lcr.loongnix.cn/library/alpine:3.24"
    note "拉取测试镜像 $TEST_IMG"
    PULLLOG="$(mktemp)"
    if docker pull -q "$TEST_IMG" >"$PULLLOG" 2>&1; then
        OUT="$(docker run --rm "$TEST_IMG" uname -m 2>/dev/null || true)"
        if [ -n "$OUT" ]; then
            ok "容器运行正常，输出 $OUT"
        else
            warn "镜像已拉取，容器未能运行"
            docker run --rm "$TEST_IMG" uname -m 2>&1 | tail -n 3 | sed 's/^/      /'
        fi
    else
        warn "测试镜像拉取失败，已完成的安装不受影响"
        tail -n 3 "$PULLLOG" | sed 's/^/      /'
        warn "若提示 no matching manifest，说明该镜像未提供 loong64 版本，请更换镜像"
    fi
    rm -f "$PULLLOG"
else
    note "按参数要求跳过测试容器"
fi

# ---------- 完成 ----------
printf '\n'
ok "安装完成"
printf '\n'
cat <<'TIP'
常用命令
  docker ps                 查看运行中的容器
  docker images             查看本地镜像
  docker compose up -d      启动 compose 服务
  docker system df          查看磁盘占用

镜像来源
  请优先使用 lcr.loongnix.cn 提供的 loong64 镜像，例如
    lcr.loongnix.cn/library/nginx:1.28.0
    lcr.loongnix.cn/library/redis:7.4.1
    lcr.loongnix.cn/library/postgres:17-sid
  Docker Hub 上的镜像大多未提供 loong64 版本，拉取时会提示 no matching manifest
TIP
printf '\n'
