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

REPO_ROOT="${ZHCTPROMPT_REPO_ROOT:-/opt/zhct/zhctprompt}"
COMPOSE_FILE="${WECOM_AIBOT_COMPOSE_FILE:-$REPO_ROOT/docker/wecom-aibot.cloud.compose.yml}"
STATE_DIR="${WECOM_AIBOT_STATE_DIR:-/var/lib/zhct-wecom-aibot}"
STATE_FILE="$STATE_DIR/deployed-inputs.sha256"
LOCK_FILE="${WECOM_AIBOT_DEPLOY_LOCK_FILE:-/run/lock/zhct-wecom-aibot-deploy.lock}"
CONTAINER_NAME="${WECOM_AIBOT_CONTAINER_NAME:-zhct-wecom-aibot}"
IMAGE_NAME="${WECOM_AIBOT_IMAGE_NAME:-zhct-wecom-aibot:cloud}"
ROLLBACK_IMAGE="${WECOM_AIBOT_ROLLBACK_IMAGE:-zhct-wecom-aibot:rollback}"
HEALTH_TIMEOUT="${WECOM_AIBOT_HEALTH_TIMEOUT:-180}"

log() {
  printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S %z')" "$*"
}

fail() {
  log "ERROR: $*" >&2
  exit 1
}

deployment_fingerprint() {
  local files=(
    control/wecom-aibot/Dockerfile.cloud
    control/wecom-aibot/package.json
    control/wecom-aibot/package-lock.json
    control/wecom-aibot/bot.js
    control/wecom-aibot/agihunt-store.py
    control/wecom-aibot/task-center.js
    control/wecom-aibot/readonly-query.php
    docker/wecom-aibot.cloud.compose.yml
  )
  (
    cd "$REPO_ROOT"
    sha256sum "${files[@]}" | sha256sum | cut -d' ' -f1
  )
}

wait_for_healthy_authentication() {
  local deadline=$((SECONDS + HEALTH_TIMEOUT))
  local health

  while (( SECONDS < deadline )); do
    health="$(docker inspect --format '{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}' "$CONTAINER_NAME" 2>/dev/null || true)"
    if [[ "$health" == "healthy" ]] \
      && docker logs "$CONTAINER_NAME" 2>&1 | grep -Fq 'Authentication successful'; then
      return 0
    fi
    if [[ "$health" == "unhealthy" || "$health" == "exited" || "$health" == "dead" ]]; then
      return 1
    fi
    sleep 3
  done
  return 1
}

rollback() {
  log "deployment failed; restoring previous image"
  docker logs --tail 100 "$CONTAINER_NAME" 2>&1 || true
  if ! docker image inspect "$ROLLBACK_IMAGE" >/dev/null 2>&1; then
    fail "no previous image is available for rollback"
  fi
  docker image tag "$ROLLBACK_IMAGE" "$IMAGE_NAME"
  docker compose -f "$COMPOSE_FILE" up -d --force-recreate --no-build
  wait_for_healthy_authentication \
    || fail "rollback container did not become healthy and authenticated"
  log "rollback completed"
  exit 1
}

command -v docker >/dev/null || fail "docker is not installed"
command -v flock >/dev/null || fail "flock is not installed"
[[ -f "$COMPOSE_FILE" ]] || fail "compose file not found: $COMPOSE_FILE"
[[ -r /opt/zhct/local/wecom.env ]] || fail "WeCom environment file is missing"

exec 9>"$LOCK_FILE"
flock -n 9 || fail "another deployment is running"
mkdir -p "$STATE_DIR"

fingerprint="$(deployment_fingerprint)"
if [[ -r "$STATE_FILE" ]] && [[ "$(<"$STATE_FILE")" == "$fingerprint" ]] \
  && [[ "$(docker inspect --format '{{.State.Status}}' "$CONTAINER_NAME" 2>/dev/null || true)" == "running" ]]; then
  log "deployment inputs unchanged; container is already running"
  exit 0
fi

cd "$REPO_ROOT"
docker compose -f "$COMPOSE_FILE" config --quiet

old_image_id="$(docker inspect --format '{{.Image}}' "$CONTAINER_NAME" 2>/dev/null || true)"
if [[ -n "$old_image_id" ]]; then
  docker image tag "$old_image_id" "$ROLLBACK_IMAGE"
fi

log "building WeCom AI bot image for fingerprint ${fingerprint:0:12}"
docker compose -f "$COMPOSE_FILE" build
docker compose -f "$COMPOSE_FILE" up -d --force-recreate --remove-orphans

if ! wait_for_healthy_authentication; then
  rollback
fi

printf '%s\n' "$fingerprint" >"$STATE_FILE"
log "deployment completed: container is healthy and authenticated"
