#!/usr/bin/env bash
set -euo pipefail

DISK="/dev/sdb"
PART="${DISK}1"

NEW_VG="docker_vg"
NEW_LV="docker_lv"
MOUNT_POINT="/var/lib/docker"
FS_TYPE="ext4"     # 可改 ext4
LV_SIZE="100%FREE"

log() {
  echo -e "\n[INFO] $*"
}

warn() {
  echo -e "\n[WARN] $*" >&2
}

die() {
  echo -e "\n[ERROR] $*" >&2
  exit 1
}

require_cmd() {
  command -v "$1" >/dev/null 2>&1 || die "缺少命令: $1"
}

cleanup_mounts_on_disk() {
  log "检查 ${DISK} 相关挂载点"
  mapfile -t mps < <(lsblk -nrpo NAME,MOUNTPOINT "${DISK}" | awk '$2 != "" {print $2}' | sort -u)

  if [[ ${#mps[@]} -gt 0 ]]; then
    warn "发现 ${DISK} 上存在挂载点: ${mps[*]}"
    for mp in "${mps[@]}"; do
      if mountpoint -q "$mp"; then
        log "卸载挂载点: $mp"
        umount -f "$mp" || die "无法卸载 $mp"
      fi
    done
  else
    log "未发现 ${DISK} 的活动挂载点"
  fi
}

stop_docker() {
  log "停止 Docker 相关服务"
  systemctl stop docker 2>/dev/null || true
  systemctl stop docker.socket 2>/dev/null || true
  systemctl stop containerd 2>/dev/null || true
}

deactivate_old_lvm() {
  log "检查旧 LVM 信息"

  # 尝试识别 /dev/sdb 或 /dev/sdb1 所属 VG
  local old_vg=""
  old_vg="$(pvs --noheadings -o vg_name "${DISK}" 2>/dev/null | awk '{$1=$1;print}' | head -n1 || true)"

  if [[ -z "${old_vg}" && -b "${PART}" ]]; then
    old_vg="$(pvs --noheadings -o vg_name "${PART}" 2>/dev/null | awk '{$1=$1;print}' | head -n1 || true)"
  fi

  if [[ -n "${old_vg}" ]]; then
    warn "发现旧 VG: ${old_vg}"

    log "列出旧 LV"
    lvs --noheadings -o lv_name "${old_vg}" 2>/dev/null | awk '{$1=$1;print}' || true

    # 尝试卸载该 VG 下所有 LV 的挂载
    while read -r lv; do
      [[ -z "${lv}" ]] && continue
      local lv_path="/dev/${old_vg}/${lv}"
      if [[ -e "${lv_path}" ]]; then
        local mp
        mp="$(lsblk -nrpo MOUNTPOINT "${lv_path}" 2>/dev/null | awk 'NF{print; exit}' || true)"
        if [[ -n "${mp}" && "${mp}" != "[SWAP]" ]]; then
          log "卸载 LV 挂载点: ${mp}"
          umount -f "${mp}" || true
        fi
      fi
    done < <(lvs --noheadings -o lv_name "${old_vg}" 2>/dev/null | awk '{$1=$1;print}')

    log "停用 VG: ${old_vg}"
    vgchange -an "${old_vg}" || true

    # 再次激活以便删除 LV，部分系统需要先处于可见状态
    vgchange -ay "${old_vg}" || true

    # 删除该 VG 下所有 LV
    while read -r lv; do
      [[ -z "${lv}" ]] && continue
      local lv_path="/dev/${old_vg}/${lv}"
      if [[ -e "${lv_path}" ]]; then
        log "删除旧 LV: ${lv_path}"
        lvremove -ff -y "${lv_path}" || true
      fi
    done < <(lvs --noheadings -o lv_name "${old_vg}" 2>/dev/null | awk '{$1=$1;print}')

    log "停用并删除旧 VG: ${old_vg}"
    vgchange -an "${old_vg}" || true
    vgremove -ff -y "${old_vg}" || true
  else
    log "未发现 ${DISK} / ${PART} 上关联的 VG"
  fi

  # 删除旧 PV
  if pvs "${PART}" >/dev/null 2>&1; then
    log "删除旧 PV: ${PART}"
    pvremove -ff -y "${PART}" || true
  fi

  if pvs "${DISK}" >/dev/null 2>&1; then
    log "删除旧 PV: ${DISK}"
    pvremove -ff -y "${DISK}" || true
  fi

  # 额外清理 device-mapper 残留
  log "清理可能遗留的 device-mapper 映射"
  dmsetup remove_all 2>/dev/null || true
  udevadm settle || true
}

wipe_disk() {
  log "清理磁盘签名和分区表: ${DISK}"

  swapoff -a 2>/dev/null || true

  wipefs -a "${PART}" 2>/dev/null || true
  wipefs -a "${DISK}" 2>/dev/null || true

  sgdisk --zap-all "${DISK}" || true
  dd if=/dev/zero of="${DISK}" bs=1M count=20 conv=fsync status=none || true

  sync
  partprobe "${DISK}" || true
  blockdev --rereadpt "${DISK}" || true
  udevadm settle || true

  # 如果分区节点还在，尝试删除
  if [[ -b "${PART}" ]]; then
    warn "${PART} 仍然存在，尝试删除分区表项"
    parted -s "${DISK}" rm 1 2>/dev/null || true
    partprobe "${DISK}" || true
    udevadm settle || true
  fi
}

prepare_mountpoint() {
  log "准备挂载目录: ${MOUNT_POINT}"

  if mountpoint -q "${MOUNT_POINT}"; then
    umount -f "${MOUNT_POINT}" || die "无法卸载 ${MOUNT_POINT}"
  fi

  mkdir -p "${MOUNT_POINT}"

  if [[ -n "$(ls -A "${MOUNT_POINT}" 2>/dev/null || true)" ]]; then
    local backup_dir="${MOUNT_POINT}.bak.$(date +%F_%H%M%S)"
    warn "${MOUNT_POINT} 非空，备份到 ${backup_dir}"
    mv "${MOUNT_POINT}" "${backup_dir}"
    mkdir -p "${MOUNT_POINT}"
  fi
}

create_new_lvm() {
  log "在整块磁盘 ${DISK} 上创建新的 LVM"

  pvcreate -ff -y "${DISK}"
  vgcreate "${NEW_VG}" "${DISK}"
  lvcreate -n "${NEW_LV}" -l "${LV_SIZE}" "${NEW_VG}"

  local lv_path="/dev/${NEW_VG}/${NEW_LV}"

  log "格式化文件系统: ${FS_TYPE}"
  if [[ "${FS_TYPE}" == "xfs" ]]; then
    mkfs.xfs -f "${lv_path}"
  elif [[ "${FS_TYPE}" == "ext4" ]]; then
    mkfs.ext4 -F "${lv_path}"
  else
    die "不支持的文件系统: ${FS_TYPE}"
  fi

  local uuid
  uuid="$(blkid -s UUID -o value "${lv_path}")"
  [[ -n "${uuid}" ]] || die "获取 UUID 失败"

  log "写入 /etc/fstab"
  cp /etc/fstab "/etc/fstab.bak.$(date +%F_%H%M%S)"
  sed -i "\|[[:space:]]${MOUNT_POINT}[[:space:]]|d" /etc/fstab
  echo "UUID=${uuid} ${MOUNT_POINT} ${FS_TYPE} defaults 0 0" >> /etc/fstab

  log "挂载 ${MOUNT_POINT}"
  mount -a

  log "挂载结果校验"
  df -TH "${MOUNT_POINT}"
  lsblk
}

start_docker() {
  log "启动 Docker"
  systemctl daemon-reload
  systemctl start containerd 2>/dev/null || true
  systemctl start docker
  systemctl enable docker 2>/dev/null || true
}

main() {
  require_cmd lsblk
  require_cmd pvs
  require_cmd vgs
  require_cmd lvs
  require_cmd pvcreate
  require_cmd vgcreate
  require_cmd lvcreate
  require_cmd wipefs
  require_cmd sgdisk
  require_cmd partprobe
  require_cmd blkid
  require_cmd dmsetup
  require_cmd parted

  [[ "$(id -u)" -eq 0 ]] || die "请使用 root 执行"

  [[ -b "${DISK}" ]] || die "磁盘不存在: ${DISK}"

  echo "======================================================"
  echo "即将彻底清空 ${DISK} 并挂载到 ${MOUNT_POINT}"
  echo "目标 VG: ${NEW_VG}"
  echo "目标 LV: ${NEW_LV}"
  echo "文件系统: ${FS_TYPE}"
  echo "警告: 此操作会销毁 ${DISK} 上所有数据"
  echo "======================================================"
  read -r -p "确认执行请输入 YES: " ans
  [[ "${ans}" == "YES" ]] || die "用户取消"

  stop_docker
  cleanup_mounts_on_disk
  deactivate_old_lvm
  wipe_disk
  prepare_mountpoint
  create_new_lvm
  start_docker

  log "完成: ${DISK} -> /dev/${NEW_VG}/${NEW_LV} -> ${MOUNT_POINT}"
}

main "$@"