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

ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
LOG_DIR="$ROOT_DIR/logs"
LOCAL_ENV_FILE="$ROOT_DIR/.env"
VITE_ENV_FILE="$ROOT_DIR/.env.local"
MARKER_FILE="$LOG_DIR/.local-supabase-initialized"
SUPABASE_BIN="$ROOT_DIR/node_modules/.bin/supabase"
PLAYWRIGHT_BIN="$ROOT_DIR/node_modules/.bin/playwright"
EXCLUDED_SUPABASE_SERVICES="studio,imgproxy,mailpit,realtime,edge-runtime,logflare,vector,postgres-meta,supavisor"
SUPABASE_SERVICE_NAME="1688-local-supabase.service"
APP_SERVICE_NAME="1688-autoprocurement.service"

RESET_DB=0
NO_START=0
NO_SYSTEMD=0
DOCKER_WITH_SUDO=0
PNPM_VERSION="10.28.2"
PNPM_BIN=""

usage() {
  cat <<'EOF'
用法:
  bash scripts/deploy.sh [--reset-db] [--no-start] [--no-systemd]

参数:
  --reset-db     重置本地 Supabase 数据库并重新执行全部迁移
  --no-start     完成安装和构建，但不启动服务
  --no-systemd   在 Linux 上跳过 systemd，改用 nohup 后台启动
  -h, --help     显示帮助
EOF
}

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

warn() {
  printf '[deploy] WARN: %s\n' "$*" >&2
}

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

command_exists() {
  command -v "$1" >/dev/null 2>&1
}

run_sudo() {
  if [[ "${EUID}" -eq 0 ]]; then
    "$@"
    return
  fi

  if ! command_exists sudo; then
    die "当前操作需要 sudo，但系统中未找到 sudo。"
  fi

  sudo "$@"
}

node_major_version() {
  if ! command_exists node; then
    echo 0
    return
  fi

  node -p "process.versions.node.split('.')[0]" 2>/dev/null || echo 0
}

upsert_env_var() {
  local file_path="$1"
  local key="$2"
  local value="$3"
  local temp_file

  mkdir -p "$(dirname "$file_path")"
  touch "$file_path"
  temp_file="$(mktemp)"

  awk -v key="$key" -v value="$value" '
    BEGIN { updated = 0 }
    $0 ~ "^" key "=" {
      print key "=" value
      updated = 1
      next
    }
    { print }
    END {
      if (!updated) {
        print key "=" value
      }
    }
  ' "$file_path" > "$temp_file"

  mv "$temp_file" "$file_path"
}

ensure_env_template_files() {
  if [[ ! -f "$LOCAL_ENV_FILE" ]]; then
    cp "$ROOT_DIR/.env.example" "$LOCAL_ENV_FILE"
  fi

  if [[ ! -f "$VITE_ENV_FILE" ]]; then
    cat > "$VITE_ENV_FILE" <<'EOF'
VITE_SUPABASE_URL=
VITE_SUPABASE_ANON_KEY=
VITE_SUPABASE_SOURCE_FILES_BUCKET=source-files
EOF
  fi
}

read_env_value() {
  local file_path="$1"
  local key="$2"
  local fallback="${3:-}"

  if [[ ! -f "$file_path" ]]; then
    printf '%s' "$fallback"
    return
  fi

  local value
  value="$(grep -E "^${key}=" "$file_path" | tail -n 1 | cut -d '=' -f 2- || true)"
  if [[ -n "$value" ]]; then
    printf '%s' "$value"
    return
  fi

  printf '%s' "$fallback"
}

ensure_node() {
  local os_name
  local current_major
  os_name="$(uname -s)"
  current_major="$(node_major_version)"

  if [[ "$current_major" -ge 20 ]]; then
    return
  fi

  log "安装 Node.js 20+"

  case "$os_name" in
    Linux)
      if ! command_exists apt-get; then
        die "当前 Linux 发行版未检测到 apt-get，暂只自动支持 Debian/Ubuntu。"
      fi

      run_sudo apt-get update
      run_sudo apt-get install -y curl ca-certificates gnupg
      curl -fsSL https://deb.nodesource.com/setup_20.x | if [[ "${EUID}" -eq 0 ]]; then bash -; else sudo -E bash -; fi
      run_sudo apt-get install -y nodejs
      ;;
    Darwin)
      if ! command_exists brew; then
        die "macOS 上缺少 Homebrew，无法自动安装 Node.js。请先安装 brew 后重试。"
      fi
      brew install node
      ;;
    *)
      die "暂不支持自动安装 Node.js 的操作系统: $os_name"
      ;;
  esac

  if ! command_exists node || [[ "$(node_major_version)" -lt 20 ]]; then
    die "Node.js 20+ 安装失败，请手动安装后重新执行部署脚本。"
  fi
}

ensure_pnpm() {
  if command_exists pnpm; then
    PNPM_BIN="$(command -v pnpm)"
    return
  fi

  if command_exists corepack; then
    log "通过 Corepack 启用 pnpm $PNPM_VERSION"
    corepack enable
    corepack prepare "pnpm@$PNPM_VERSION" --activate
  elif [[ "$(uname -s)" == "Darwin" ]] && command_exists brew; then
    log "通过 Homebrew 安装 pnpm"
    brew install pnpm
  else
    log "通过官方安装脚本安装 pnpm $PNPM_VERSION"
    curl -fsSL https://get.pnpm.io/install.sh | env PNPM_VERSION="$PNPM_VERSION" sh -
    if [[ "$(uname -s)" == "Linux" ]]; then
      export PNPM_HOME="${PNPM_HOME:-$HOME/.local/share/pnpm}"
    else
      export PNPM_HOME="${PNPM_HOME:-$HOME/Library/pnpm}"
    fi
    export PATH="$PNPM_HOME:$PATH"
  fi

  if ! command_exists pnpm; then
    die "pnpm 安装失败，请手动安装 pnpm $PNPM_VERSION 后重试。"
  fi

  PNPM_BIN="$(command -v pnpm)"
}

ensure_docker() {
  local os_name
  os_name="$(uname -s)"

  if command_exists docker && docker info >/dev/null 2>&1; then
    DOCKER_WITH_SUDO=0
    return
  fi

  if command_exists docker && run_sudo docker info >/dev/null 2>&1; then
    DOCKER_WITH_SUDO=1
    return
  fi

  log "安装 Docker"

  case "$os_name" in
    Linux)
      if ! command_exists apt-get; then
        die "当前 Linux 发行版未检测到 apt-get，暂只自动支持 Debian/Ubuntu。"
      fi

      run_sudo apt-get update
      run_sudo apt-get install -y docker.io

      if command_exists systemctl; then
        run_sudo systemctl enable --now docker
      else
        run_sudo service docker start || true
      fi
      ;;
    Darwin)
      if command_exists colima; then
        colima start >/dev/null 2>&1 || true
      elif command_exists brew; then
        brew install --cask docker || true
        warn "已尝试安装 Docker Desktop。请确认 Docker 已启动后重新执行脚本。"
      else
        die "macOS 上未检测到可用的 Docker 运行时。请先安装并启动 Docker Desktop、Colima、OrbStack 或 Rancher Desktop。"
      fi
      ;;
    *)
      die "暂不支持自动安装 Docker 的操作系统: $os_name"
      ;;
  esac

  if command_exists docker && docker info >/dev/null 2>&1; then
    DOCKER_WITH_SUDO=0
    return
  fi

  if command_exists docker && run_sudo docker info >/dev/null 2>&1; then
    DOCKER_WITH_SUDO=1
    return
  fi

  die "Docker 已安装但当前无法访问 Docker daemon，请确认 Docker 服务已启动后重试。"
}

run_supabase() {
  if [[ ! -x "$SUPABASE_BIN" ]]; then
    die "未找到本地 Supabase CLI。请先完成 pnpm install。"
  fi

  if [[ "$DOCKER_WITH_SUDO" -eq 1 ]]; then
    run_sudo env PATH="$PATH" "$SUPABASE_BIN" "$@"
  else
    "$SUPABASE_BIN" "$@"
  fi
}

install_dependencies() {
  log "安装 Node.js workspace 依赖"
  (
    cd "$ROOT_DIR"
    "$PNPM_BIN" install --frozen-lockfile
  )
}

install_playwright_browser() {
  if [[ ! -x "$PLAYWRIGHT_BIN" ]]; then
    warn "未检测到 Playwright CLI，跳过浏览器安装。"
    return
  fi

  log "安装 Playwright Chromium 浏览器"
  if [[ "$(uname -s)" == "Linux" ]]; then
    if [[ "${EUID}" -eq 0 ]]; then
      "$PLAYWRIGHT_BIN" install --with-deps chromium
    elif command_exists sudo; then
      run_sudo env PATH="$PATH" HOME="$HOME" "$PLAYWRIGHT_BIN" install --with-deps chromium
    else
      "$PLAYWRIGHT_BIN" install chromium
    fi
  else
    "$PLAYWRIGHT_BIN" install chromium
  fi
}

ensure_local_supabase() {
  [[ -f "$ROOT_DIR/supabase/config.toml" ]] || die "缺少 supabase/config.toml，无法启动本地 Supabase。"

  log "启动本地 Supabase"
  run_supabase start --ignore-health-check --exclude "$EXCLUDED_SUPABASE_SERVICES"

  mkdir -p "$LOG_DIR"
  if [[ "$RESET_DB" -eq 1 || ! -f "$MARKER_FILE" ]]; then
    log "初始化本地 Supabase 数据库"
    run_supabase db reset --local
    date > "$MARKER_FILE"
  else
    log "应用待执行的本地 Supabase 迁移"
    run_supabase migration up --local
  fi
}

sync_local_supabase_env() {
  local status_env
  local api_url
  local anon_key
  local service_role_key
  local automation_port

  status_env="$(run_supabase status -o env)"
  api_url="$(printf '%s\n' "$status_env" | awk '/^API_URL=/{sub(/^API_URL=/, ""); print}')"
  anon_key="$(printf '%s\n' "$status_env" | awk '/^ANON_KEY=/{sub(/^ANON_KEY=/, ""); print}')"
  service_role_key="$(printf '%s\n' "$status_env" | awk '/^SERVICE_ROLE_KEY=/{sub(/^SERVICE_ROLE_KEY=/, ""); print}')"

  [[ -n "$api_url" ]] || die "未能从本地 Supabase 读取 API_URL。"
  [[ -n "$anon_key" ]] || die "未能从本地 Supabase 读取 ANON_KEY。"
  [[ -n "$service_role_key" ]] || die "未能从本地 Supabase 读取 SERVICE_ROLE_KEY。"

  ensure_env_template_files

  upsert_env_var "$LOCAL_ENV_FILE" SUPABASE_URL "$api_url"
  upsert_env_var "$LOCAL_ENV_FILE" SUPABASE_ANON_KEY "$anon_key"
  upsert_env_var "$LOCAL_ENV_FILE" SUPABASE_SERVICE_ROLE_KEY "$service_role_key"
  upsert_env_var "$LOCAL_ENV_FILE" SUPABASE_service_key "$service_role_key"
  upsert_env_var "$LOCAL_ENV_FILE" VITE_SUPABASE_URL "$api_url"
  upsert_env_var "$LOCAL_ENV_FILE" VITE_SUPABASE_ANON_KEY "$anon_key"
  upsert_env_var "$LOCAL_ENV_FILE" VITE_SUPABASE_SOURCE_FILES_BUCKET "source-files"

  automation_port="$(read_env_value "$LOCAL_ENV_FILE" AUTOMATION_PORT 3030)"
  upsert_env_var "$LOCAL_ENV_FILE" AUTOMATION_PORT "$automation_port"

  upsert_env_var "$VITE_ENV_FILE" VITE_SUPABASE_URL "$api_url"
  upsert_env_var "$VITE_ENV_FILE" VITE_SUPABASE_ANON_KEY "$anon_key"
  upsert_env_var "$VITE_ENV_FILE" VITE_SUPABASE_SOURCE_FILES_BUCKET "source-files"
}

build_frontend() {
  log "构建前端静态资源"
  (
    cd "$ROOT_DIR"
    "$PNPM_BIN" run build
  )
}

write_systemd_units() {
  local run_user
  local pnpm_path
  local supabase_service_file
  local app_service_file

  run_user="${SUDO_USER:-$USER}"
  pnpm_path="$PNPM_BIN"
  supabase_service_file="/etc/systemd/system/$SUPABASE_SERVICE_NAME"
  app_service_file="/etc/systemd/system/$APP_SERVICE_NAME"

  cat > /tmp/$SUPABASE_SERVICE_NAME <<EOF
[Unit]
Description=1688 Autoprocurement Local Supabase
After=docker.service network-online.target
Wants=docker.service network-online.target

[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=$ROOT_DIR
ExecStart=/usr/bin/env bash -lc 'if ! "$SUPABASE_BIN" status >/dev/null 2>&1; then "$SUPABASE_BIN" start --ignore-health-check --exclude "$EXCLUDED_SUPABASE_SERVICES"; fi'
ExecStop=/usr/bin/env bash -lc '"$SUPABASE_BIN" stop || true'
TimeoutStartSec=900

[Install]
WantedBy=multi-user.target
EOF

  cat > /tmp/$APP_SERVICE_NAME <<EOF
[Unit]
Description=1688 Autoprocurement App
After=$SUPABASE_SERVICE_NAME network-online.target
Wants=$SUPABASE_SERVICE_NAME network-online.target

[Service]
Type=simple
WorkingDirectory=$ROOT_DIR
Environment=NODE_ENV=production
EnvironmentFile=$LOCAL_ENV_FILE
ExecStart=$pnpm_path run start:prod
Restart=always
RestartSec=5
User=$run_user

[Install]
WantedBy=multi-user.target
EOF

  run_sudo install -m 0644 /tmp/$SUPABASE_SERVICE_NAME "$supabase_service_file"
  run_sudo install -m 0644 /tmp/$APP_SERVICE_NAME "$app_service_file"
  rm -f /tmp/$SUPABASE_SERVICE_NAME /tmp/$APP_SERVICE_NAME

  run_sudo systemctl daemon-reload
}

start_with_systemd() {
  log "通过 systemd 注册并启动服务"
  write_systemd_units
  run_sudo systemctl enable --now "$SUPABASE_SERVICE_NAME"
  run_sudo systemctl enable --now "$APP_SERVICE_NAME"
}

start_with_nohup() {
  local pid_file
  pid_file="$LOG_DIR/app.pid"

  log "使用 nohup 后台启动应用"
  if [[ -f "$pid_file" ]]; then
    local existing_pid
    existing_pid="$(cat "$pid_file" 2>/dev/null || true)"
    if [[ -n "$existing_pid" ]] && kill -0 "$existing_pid" >/dev/null 2>&1; then
      kill "$existing_pid" >/dev/null 2>&1 || true
    fi
  fi

  (
    cd "$ROOT_DIR"
    nohup "$PNPM_BIN" run start:prod > "$LOG_DIR/app.log" 2>&1 &
    echo $! > "$pid_file"
  )
}

print_post_deploy_summary() {
  local automation_port
  automation_port="$(read_env_value "$LOCAL_ENV_FILE" AUTOMATION_PORT 3030)"

  log "部署完成"
  log "应用地址: http://127.0.0.1:$automation_port"
  log "本地 Supabase API: http://127.0.0.1:54321"
  log "本地 Supabase DB: postgresql://postgres:postgres@127.0.0.1:54322/postgres"

  if [[ -z "$(read_env_value "$LOCAL_ENV_FILE" LLM_API_KEY)" ]]; then
    warn "当前未配置 LLM_API_KEY，标准化、离线批处理和智能询价相关功能暂不可用。"
  fi

  if [[ -z "$(read_env_value "$LOCAL_ENV_FILE" LOGIN_1688_USER)" || -z "$(read_env_value "$LOCAL_ENV_FILE" LOGIN_1688_PASS)" ]]; then
    warn "当前未配置 1688 登录账号，自动搜索/自动询价在补齐账号前无法执行。"
  fi
}

main() {
  while [[ $# -gt 0 ]]; do
    case "$1" in
      --reset-db)
        RESET_DB=1
        ;;
      --no-start)
        NO_START=1
        ;;
      --no-systemd)
        NO_SYSTEMD=1
        ;;
      -h|--help)
        usage
        exit 0
        ;;
      *)
        die "未知参数: $1"
        ;;
    esac
    shift
  done

  mkdir -p "$LOG_DIR"

  ensure_node
  ensure_pnpm
  ensure_docker
  install_dependencies
  install_playwright_browser
  ensure_local_supabase
  sync_local_supabase_env
  build_frontend

  if [[ "$NO_START" -eq 0 ]]; then
    if [[ "$(uname -s)" == "Linux" ]] && command_exists systemctl && [[ "$NO_SYSTEMD" -eq 0 ]]; then
      start_with_systemd
    else
      start_with_nohup
    fi
  fi

  print_post_deploy_summary
}

main "$@"
