#!/usr/bin/env bash
# 在线订餐管理系统后台 Docker Compose 启动脚本（仅后台容器，MySQL/Redis 使用现网）
# 默认镜像: harbor.sxidc.com/ywzx/fenyangwenlv:v1.0.0
#
# 用法：
#   ./start.sh up             # 本地编译 + 构建镜像 + 启动（输出精简）
#   ./start.sh up --pull      # 从 Harbor 拉取镜像并启动
#   ./start.sh up -v          # 显示完整编译/构建日志
#   ./start.sh pull           # 仅拉取镜像
#   ./start.sh push           # 本地打包、构建并推送到 Harbor（需 docker login harbor.sxidc.com）
#   ./start.sh build          # 本地构建镜像（不打 tag 推送）
#   ./start.sh build-jar      # 仅 Maven 打包
#   ./start.sh logs           # 查看日志
#   ./start.sh down           # 停止容器

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
MAVEN_ROOT=""
BUILD_CONTEXT=""
DOCKER_DIR=""
ENV_FILE=""
COMPOSE_FILE=""
DOCKERFILE_PATH=""

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'

log_info()  { echo -e "${GREEN}[INFO]${NC} $*"; }
log_warn()  { echo -e "${YELLOW}[WARN]${NC} $*"; }
log_error() { echo -e "${RED}[ERROR]${NC} $*"; }

require_cmd() {
  if ! command -v "$1" >/dev/null 2>&1; then
    log_error "未找到命令: $1"
    exit 1
  fi
}

load_env() {
  # shellcheck disable=SC1090
  set -a
  source "${ENV_FILE}" 2>/dev/null || true
  set +a
}

# 判断目录是否为 Maven 多模块根（含 web-starter 子模块）
is_maven_project_root() {
  local dir="$1"
  [[ -f "${dir}/pom.xml" && -f "${dir}/web-starter/pom.xml" ]]
}

# 解析 docker 目录、compose 文件与 Maven 工程根（兼容脚本在 docker/ 或部署根目录两种布局）
init_paths() {
  if [[ -f "${SCRIPT_DIR}/docker-compose.yml" ]]; then
    DOCKER_DIR="${SCRIPT_DIR}"
  elif [[ -f "${SCRIPT_DIR}/docker/docker-compose.yml" ]]; then
    DOCKER_DIR="${SCRIPT_DIR}/docker"
  else
    log_error "未找到 docker-compose.yml（请在 docker/ 目录或部署根目录执行 start.sh）"
    exit 1
  fi

  ENV_FILE="${DOCKER_DIR}/.env"
  COMPOSE_FILE="${DOCKER_DIR}/docker-compose.yml"

  if [[ -f "${DOCKER_DIR}/Dockerfile" ]]; then
    DOCKERFILE_PATH="${DOCKER_DIR}/Dockerfile"
  else
    DOCKERFILE_PATH="${DOCKER_DIR}/docker/Dockerfile"
  fi

  # 先读 .env，允许 PROJECT_ROOT 显式指定 Maven 根
  if [[ -f "${ENV_FILE}" ]]; then
    load_env
  fi

  local from_env="${PROJECT_ROOT:-}"
  MAVEN_ROOT=""
  if [[ -n "${from_env}" ]] && is_maven_project_root "${from_env}"; then
    MAVEN_ROOT="$(cd "${from_env}" && pwd)"
  else
    local candidate
    for candidate in \
      "${SCRIPT_DIR}" \
      "${SCRIPT_DIR}/.." \
      "${DOCKER_DIR}" \
      "${DOCKER_DIR}/.." \
      "${DOCKER_DIR}/../TravelWebSystem" \
      "${SCRIPT_DIR}/TravelWebSystem"; do
      if is_maven_project_root "${candidate}"; then
        MAVEN_ROOT="$(cd "${candidate}" && pwd)"
        break
      fi
    done
  fi

  BUILD_CONTEXT="${MAVEN_ROOT:-${DOCKER_DIR}}"
  export MAVEN_ROOT
  export BUILD_CONTEXT
  export PROJECT_ROOT="${BUILD_CONTEXT}"
  export DOCKERFILE_PATH
}

compose() {
  if docker compose version >/dev/null 2>&1; then
    docker compose --env-file "${ENV_FILE}" -f "${COMPOSE_FILE}" "$@"
  elif command -v docker-compose >/dev/null 2>&1; then
    docker-compose --env-file "${ENV_FILE}" -f "${COMPOSE_FILE}" "$@"
  else
    log_error "未找到 docker compose / docker-compose，请安装 Docker Compose v2"
    exit 1
  fi
}

default_jar_path() {
  echo "${APP_JAR:-web-starter/target/web-starter-1.0-SNAPSHOT.jar}"
}

resolved_jar() {
  local jar
  jar="$(default_jar_path)"
  if [[ "${jar}" = /* ]]; then
    echo "${jar}"
  else
    echo "${BUILD_CONTEXT}/${jar}"
  fi
}

ensure_env() {
  if [[ ! -f "${ENV_FILE}" ]]; then
    if [[ -f "${SCRIPT_DIR}/.env.example" ]]; then
      cp "${SCRIPT_DIR}/.env.example" "${ENV_FILE}"
      log_warn "已生成 ${ENV_FILE}，请填写现网 MYSQL_* / REDIS_* 后再启动"
    else
      log_error "缺少 ${ENV_FILE} 与 .env.example"
      exit 1
    fi
  fi
  load_env
  local missing=0
  for key in MYSQL_HOST MYSQL_USER MYSQL_PASSWORD REDIS_HOST; do
    if ! grep -q "^${key}=." "${ENV_FILE}" 2>/dev/null; then
      log_error ".env 缺少或未填写: ${key}"
      missing=1
    fi
    local val
    val="$(grep "^${key}=" "${ENV_FILE}" | cut -d= -f2- | tr -d '\r')"
    if [[ -z "${val}" || "${val}" == "请填写现网密码" ]]; then
      log_error ".env 中 ${key} 仍为占位值，请改成现网配置"
      missing=1
    fi
  done
  if [[ "${missing}" -eq 1 ]]; then
    exit 1
  fi
  mkdir -p "${DOCKER_DIR}/config"
}

ensure_docker() {
  require_cmd docker
  if ! docker info >/dev/null 2>&1; then
    log_error "Docker 未运行，请先启动 Docker Desktop / dockerd"
    exit 1
  fi
}

image_name() {
  load_env
  echo "${DOCKER_IMAGE:-harbor.sxidc.com/ywzx/fenyangwenlv:v1.0.0}"
}

BUILD_LOG=""
COMPOSE_LOG=""

is_verbose() {
  [[ "${VERBOSE:-0}" -eq 1 ]]
}

ensure_jar() {
  local jar
  jar="$(resolved_jar)"

  if [[ -f "${jar}" && "${SKIP_MAVEN_BUILD:-0}" == "1" ]]; then
    log_info "已存在 JAR，跳过 Maven 编译: ${jar}"
    return 0
  fi

  if [[ -z "${MAVEN_ROOT}" ]]; then
    if [[ -f "${jar}" ]]; then
      log_warn "未找到 Maven 工程根目录，使用已有 JAR: ${jar}"
      return 0
    fi
    log_error "未找到 Maven 工程（缺少 pom.xml 与 web-starter 模块）"
    log_error "请任选其一："
    log_error "  1) 在 .env 设置 PROJECT_ROOT=完整源码目录（含 pom.xml、web-starter/）"
    log_error "  2) 放置 JAR 到 ${jar} 并设置 SKIP_MAVEN_BUILD=1"
    log_error "  3) 使用 Harbor 镜像: ./start.sh up --pull"
    exit 1
  fi

  require_cmd mvn
  log_info "Maven 工程根: ${MAVEN_ROOT}"

  if is_verbose; then
    log_info "Maven 打包 web-starter（跳过测试）..."
    (cd "${MAVEN_ROOT}" && mvn -B -f pom.xml -pl web-starter -am package -DskipTests)
  else
    log_info "正在编译..."
    : > "${BUILD_LOG}"
    if ! (cd "${MAVEN_ROOT}" && mvn -B -q -f pom.xml -pl web-starter -am package -DskipTests >>"${BUILD_LOG}" 2>&1); then
      log_error "编译失败，日志: ${BUILD_LOG}"
      tail -n 50 "${BUILD_LOG}" >&2
      exit 1
    fi
  fi

  if [[ ! -f "${jar}" ]]; then
    log_error "未找到构建产物: ${jar}"
    exit 1
  fi
}

compose_up_build() {
  if is_verbose; then
    log_info "构建镜像并启动容器..."
    compose up -d --build
    return
  fi

  log_info "正在构建镜像并启动..."
  : > "${COMPOSE_LOG}"
  if ! compose up -d --build --quiet-pull >>"${COMPOSE_LOG}" 2>&1; then
    log_error "构建或启动失败，日志: ${COMPOSE_LOG}"
    tail -n 50 "${COMPOSE_LOG}" >&2
    exit 1
  fi
}

compose_build() {
  if is_verbose; then
    compose build backend
    return
  fi
  : > "${COMPOSE_LOG}"
  if ! compose build backend >>"${COMPOSE_LOG}" 2>&1; then
    log_error "镜像构建失败，日志: ${COMPOSE_LOG}"
    tail -n 50 "${COMPOSE_LOG}" >&2
    exit 1
  fi
}

print_endpoints() {
  log_info "镜像: $(image_name)"
  log_info "后台 API: http://localhost:${SERVER_PORT:-8086}"
  log_info "Swagger:  http://localhost:${SERVER_PORT:-8086}/swagger-ui.html"
  log_info "MySQL: ${MYSQL_HOST}:${MYSQL_PORT:-3306}/${MYSQL_DATABASE:-xinghc_travel}"
  log_info "Redis: ${REDIS_HOST}:${REDIS_PORT:-6379} db=${REDIS_DB:-1}"
  log_info "查看日志: ${SCRIPT_DIR}/start.sh logs"
}

cmd_pull() {
  ensure_docker
  ensure_env
  log_info "拉取镜像 $(image_name) ..."
  compose pull backend
}

cmd_up() {
  local do_pull=0
  local do_no_build=0
  VERBOSE=0
  for arg in "$@"; do
    case "${arg}" in
      --pull) do_pull=1 ;;
      --no-build) do_no_build=1 ;;
      -v|--verbose) VERBOSE=1 ;;
    esac
  done

  ensure_docker
  ensure_env

  if [[ "${do_pull}" -eq 1 ]]; then
    log_info "拉取镜像并启动: $(image_name)"
    compose pull backend
    compose up -d
  elif [[ "${do_no_build}" -eq 1 ]]; then
    log_info "启动已有镜像: $(image_name)"
    compose up -d
  else
    log_info "构建并启动后台: $(image_name)"
    ensure_jar
    compose_up_build
    log_info "启动完成"
  fi

  compose ps
  print_endpoints
}

cmd_build() {
  ensure_docker
  ensure_env
  VERBOSE="${VERBOSE:-0}"
  if [[ ! -f "$(resolved_jar)" ]]; then
    ensure_jar
  fi
  log_info "构建镜像: $(image_name)"
  compose_build
}

cmd_push() {
  ensure_docker
  ensure_env
  VERBOSE="${VERBOSE:-0}"
  ensure_jar
  local img
  img="$(image_name)"
  log_info "构建并推送: ${img}"
  compose_build
  docker push "${img}"
  log_info "推送完成: ${img}"
}

cmd_logs() {
  ensure_docker
  ensure_env
  compose logs -f --tail=200 backend
}

cmd_down() {
  ensure_docker
  ensure_env
  if [[ "${1:-}" == "-v" ]]; then
    log_warn "将删除 backend 数据卷（上传文件、日志等）"
    compose down -v
  else
    compose down
  fi
}

cmd_ps() {
  ensure_docker
  ensure_env
  compose ps -a
}

cmd_restart() {
  ensure_docker
  ensure_env
  compose restart backend
}

usage() {
  cat <<EOF
用法: $(basename "$0") <command>

命令:
  up [--pull] [--no-build] [-v]  构建并启动（--pull 用 Harbor；--no-build 不编译/不构建镜像）
  pull          仅拉取 Harbor 镜像
  push          本地打包、构建并 push 到 Harbor（需 docker login）
  build         仅本地构建镜像
  build-jar     仅 Maven 打包
  logs          跟踪 backend 日志
  ps            查看容器状态
  restart       重启 backend
  down          停止容器（保留数据卷）
  down -v       停止并删除数据卷

环境变量（.env）:
  DOCKER_IMAGE        默认 harbor.sxidc.com/ywzx/fenyangwenlv:v1.0.0
  PROJECT_ROOT        Maven 工程根（含 pom.xml、web-starter/）；未设置则自动探测
  SKIP_MAVEN_BUILD=1  跳过 mvn，使用已有 JAR
  SPRING_ARGS             传给 java -jar 的 Spring 参数（如 --spring.config.location=...）
  HOST_CONFIG_DIR         宿主机配置目录，挂载为 /serverdata/config（默认 ./config）

外部配置: 复制 config/application.yaml.example 为 config/application.yaml 后修改
EOF
}

main() {
  init_paths
  BUILD_LOG="${DOCKER_DIR}/.build.log"
  COMPOSE_LOG="${DOCKER_DIR}/.compose.log"

  local cmd="${1:-up}"
  shift || true

  case "${cmd}" in
    up)        cmd_up "$@" ;;
    pull)      cmd_pull ;;
    push)      cmd_push ;;
    build)     cmd_build ;;
    build-jar) VERBOSE=1; ensure_jar ;;
    logs)      cmd_logs ;;
    down)      cmd_down "$@" ;;
    ps)        cmd_ps ;;
    restart)   cmd_restart ;;
    -h|--help|help) usage ;;
    *)
      log_error "未知命令: ${cmd}"
      usage
      exit 1
      ;;
  esac
}

main "$@"
