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

SMARTDNS_CONF="${SMARTDNS_CONF:-/etc/smartdns/smartdns.conf}"
SMARTDNS_CACHE_SIZE="${SMARTDNS_CACHE_SIZE:-65536}"
SMARTDNS_LISTEN_PORT="${SMARTDNS_LISTEN_PORT:-53}"
LOCAL_DNS_ADDR="${LOCAL_DNS_ADDR:-127.0.0.1}"
WORKDIR="$(mktemp -d /tmp/smartdns-install.XXXXXX)"

cleanup() {
  rm -rf "$WORKDIR"
}
trap cleanup EXIT

log() {
  printf '[INFO] %s\n' "$*"
}

die() {
  printf '[ERROR] %s\n' "$*" >&2
  exit 1
}

require_root() {
  if [[ "${EUID}" -ne 0 ]]; then
    die "请使用 root 运行此脚本。"
  fi
}

detect_os() {
  [[ -r /etc/os-release ]] || die "/etc/os-release 不存在，无法识别系统。"
  # shellcheck disable=SC1091
  . /etc/os-release

  OS_ID="${ID:-}"
  OS_VERSION_ID="${VERSION_ID:-}"
  OS_MAJOR="${OS_VERSION_ID%%.*}"

  case "${OS_ID}" in
    centos|rhel|rocky|almalinux)
      if [[ "${OS_MAJOR}" != "7" && "${OS_MAJOR}" != "9" ]]; then
        die "当前仅针对 CentOS/RHEL 7 和 9 系列做了验证，检测到版本: ${OS_VERSION_ID}"
      fi
      OS_FAMILY="rhel"
      ;;
    debian)
      if [[ "${OS_MAJOR}" != "12" && "${OS_MAJOR}" != "13" ]]; then
        die "当前仅针对 Debian 12 和 13 做了验证，检测到版本: ${OS_VERSION_ID}"
      fi
      OS_FAMILY="debian"
      ;;
    *)
      die "不支持的系统: ${OS_ID:-unknown}"
      ;;
  esac
}

detect_arch() {
  local raw_arch
  raw_arch="$(uname -m)"

  case "${raw_arch}" in
    x86_64|amd64)
      SMARTDNS_ARCH="x86_64"
      ;;
    aarch64|arm64)
      SMARTDNS_ARCH="aarch64"
      ;;
    armv7l|armv7|armhf)
      SMARTDNS_ARCH="arm"
      ;;
    *)
      die "不支持的 CPU 架构: ${raw_arch}"
      ;;
  esac
}

install_dependencies() {
  if [[ "${OS_FAMILY}" == "debian" ]]; then
    export DEBIAN_FRONTEND=noninteractive
    apt-get update
    apt-get install -y ca-certificates curl python3 tar gzip
  else
    if command -v dnf >/dev/null 2>&1; then
      dnf install -y ca-certificates curl python3 tar gzip
    else
      yum install -y ca-certificates curl python3 tar gzip
    fi
  fi
}

get_release_info() {
  local out
  out="$(python3 - <<'PY'
import json
import urllib.request

url = "https://api.github.com/repos/pymumu/smartdns/releases/latest"
with urllib.request.urlopen(url, timeout=30) as r:
    data = json.load(r)

print(data["tag_name"])
for asset in data["assets"]:
    print(f'{asset["name"]}\t{asset["browser_download_url"]}')
PY
)"

  RELEASE_TAG="$(printf '%s\n' "${out}" | head -n1)"
  RELEASE_ASSETS="$(printf '%s\n' "${out}" | tail -n +2)"
  [[ -n "${RELEASE_TAG}" ]] || die "无法获取 SmartDNS 最新版本信息。"
}

pick_asset() {
  if [[ "${OS_FAMILY}" == "debian" ]]; then
    ASSET_NAME_PATTERN="smartdns\\..*\\.${SMARTDNS_ARCH}-debian-all\\.deb"
  else
    ASSET_NAME_PATTERN="smartdns\\..*\\.${SMARTDNS_ARCH}-linux-all\\.tar\\.gz"
  fi

  ASSET_LINE="$(printf '%s\n' "${RELEASE_ASSETS}" | grep -E "${ASSET_NAME_PATTERN}" | head -n1 || true)"
  [[ -n "${ASSET_LINE}" ]] || die "未找到适用于当前系统的 SmartDNS 安装包。"

  ASSET_NAME="$(printf '%s' "${ASSET_LINE}" | cut -f1)"
  ASSET_URL="$(printf '%s' "${ASSET_LINE}" | cut -f2)"
}

download_asset() {
  ASSET_PATH="${WORKDIR}/${ASSET_NAME}"
  log "下载 ${ASSET_NAME}"
  curl -fL --retry 3 --connect-timeout 15 -o "${ASSET_PATH}" "${ASSET_URL}"
}

install_smartdns() {
  if [[ "${OS_FAMILY}" == "debian" ]]; then
    dpkg -i "${ASSET_PATH}" || apt-get install -f -y
  else
    tar -xzf "${ASSET_PATH}" -C "${WORKDIR}"
    local install_script
    local install_output
    local install_rc
    install_script="$(find "${WORKDIR}" -maxdepth 3 -type f -name install | head -n1)"
    [[ -n "${install_script}" ]] || die "未找到 SmartDNS 安装脚本。"
    chmod +x "${install_script}"
    set +e
    install_output="$("${install_script}" -i 2>&1)"
    install_rc=$?
    set -e
    printf '%s\n' "${install_output}"

    if [[ ${install_rc} -ne 0 ]] && ! printf '%s\n' "${install_output}" | grep -qi 'Already installed'; then
      die "SmartDNS 安装失败。"
    fi
  fi
}

backup_config() {
  mkdir -p "$(dirname "${SMARTDNS_CONF}")"
  if [[ -f "${SMARTDNS_CONF}" ]]; then
    cp -a "${SMARTDNS_CONF}" "${SMARTDNS_CONF}.bak.$(date +%Y%m%d%H%M%S)"
  fi
}

backup_file() {
  local file_path="$1"
  if [[ -e "${file_path}" || -L "${file_path}" ]]; then
    cp -a "${file_path}" "${file_path}.bak.$(date +%Y%m%d%H%M%S)"
  fi
}

write_config() {
  cat > "${SMARTDNS_CONF}" <<EOF
bind 127.0.0.1:${SMARTDNS_LISTEN_PORT}
bind [::1]:${SMARTDNS_LISTEN_PORT}

server-name smartdns
cache-size ${SMARTDNS_CACHE_SIZE}
prefetch-domain yes
serve-expired yes
rr-ttl-min 300
rr-ttl-max 86400
log-level info

server 223.5.5.5
server 223.6.6.6
server 1.1.1.1
server 8.8.8.8

address /www.hsbc.com.cn/#6
address /cp.cloudflare.com/#6
address /www.gstatic.com/#6

https-record /www.hsbc.com.cn/#
https-record /cp.cloudflare.com/#
https-record /www.gstatic.com/#
EOF
}

check_port_53() {
  local pids
  pids="$(ss -lntup 2>/dev/null | awk -v port=":${SMARTDNS_LISTEN_PORT}" '$5 ~ port {print $0}' || true)"
  if [[ -n "${pids}" ]] && ! printf '%s\n' "${pids}" | grep -qi 'smartdns'; then
    printf '%s\n' "${pids}" >&2
    die "检测到 ${SMARTDNS_LISTEN_PORT} 端口已被其他服务占用，请先释放端口后再启动 SmartDNS。"
  fi
}

enable_service() {
  systemctl daemon-reload
  check_port_53
  systemctl enable smartdns
  systemctl restart smartdns
  systemctl --no-pager --full status smartdns || true
}

configure_systemd_resolved() {
  local resolved_conf="/etc/systemd/resolved.conf"

  [[ -d /etc/systemd ]] || return 1
  if ! systemctl list-unit-files 2>/dev/null | grep -q '^systemd-resolved\.service'; then
    return 1
  fi

  backup_file "${resolved_conf}"
  mkdir -p /etc/systemd

  cat > "${resolved_conf}" <<EOF
[Resolve]
DNS=${LOCAL_DNS_ADDR}
FallbackDNS=
Domains=~.
DNSStubListener=yes
EOF

  systemctl enable systemd-resolved >/dev/null 2>&1 || true
  systemctl restart systemd-resolved

  if [[ -e /run/systemd/resolve/stub-resolv.conf ]]; then
    backup_file /etc/resolv.conf
    ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf
  fi

  log "已通过 systemd-resolved 将本机默认 DNS 指向 ${LOCAL_DNS_ADDR}"
  return 0
}

configure_resolv_conf_dns() {
  backup_file /etc/resolv.conf
  rm -f /etc/resolv.conf
  cat > /etc/resolv.conf <<EOF
nameserver ${LOCAL_DNS_ADDR}
options timeout:2 attempts:2 rotate
EOF
  chmod 644 /etc/resolv.conf
  log "已直接写入 /etc/resolv.conf，将本机默认 DNS 指向 ${LOCAL_DNS_ADDR}"
}

configure_local_resolver() {
  if configure_systemd_resolved; then
    return 0
  fi

  configure_resolv_conf_dns
}

show_verify_commands() {
  cat <<'EOF'

验证建议：
  dig A www.hsbc.com.cn @127.0.0.1
  dig AAAA www.hsbc.com.cn @127.0.0.1
  dig A cp.cloudflare.com @127.0.0.1
  dig AAAA cp.cloudflare.com @127.0.0.1
  dig A www.gstatic.com @127.0.0.1
  dig AAAA www.gstatic.com @127.0.0.1

预期结果：
  A 记录能正常返回；
  AAAA/HTTPS 记录会被 SmartDNS 抑制，因此客户端会走 IPv4 A 解析。

额外检查：
  ss -lntup | grep ':53'
  cat /etc/resolv.conf
  dig A www.gstatic.com
  dig AAAA www.gstatic.com

预期监听地址：
  127.0.0.1:53
  [::1]:53
EOF
}

main() {
  require_root
  detect_os
  detect_arch
  install_dependencies
  get_release_info
  pick_asset
  download_asset
  install_smartdns
  backup_config
  write_config
  enable_service
  configure_local_resolver

  log "SmartDNS 已安装完成。最新版本标签: ${RELEASE_TAG}"
  log "配置文件: ${SMARTDNS_CONF}"
  log "本机默认 DNS 已尝试切换到 ${LOCAL_DNS_ADDR}"
  show_verify_commands
}

main "$@"
