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

root_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
base_dir="$(cd "$root_dir/.." && pwd)"
failures=0

pass() { printf 'PASS  %s\n' "$1"; }
fail() { printf 'FAIL  %s\n' "$1"; failures=$((failures + 1)); }
info() { printf 'INFO  %s\n' "$1"; }

command -v docker >/dev/null 2>&1 || { echo "Docker is required." >&2; exit 1; }

mapfile -t edition_dirs < <(
  find "$root_dir/deploy/docker" -mindepth 1 -maxdepth 1 -type d -printf '%f\n' 2>/dev/null \
    | while read -r candidate; do
        case "$candidate" in
          mail-only|mail-google|mail-native-zimbra|mailmali-google-connect)
            [[ -f "$root_dir/deploy/docker/$candidate/docker-compose.yml" ]] && printf '%s\n' "$candidate"
            ;;
        esac
      done
)
if [[ "${#edition_dirs[@]}" != "1" ]]; then
  echo "Cannot identify Edition in this release directory." >&2
  exit 1
fi
edition="${edition_dirs[0]}"
compose_file="$root_dir/deploy/docker/$edition/docker-compose.yml"
volume_name="${BACKEND_DATA_VOLUME:-${edition}_backend-data}"
compose_project="${COMPOSE_PROJECT_NAME:-}"
runtime_project=""

# The volume label is normally authoritative, but older installs may have
# been started from a different directory and therefore use another project
# name. Find the project from the running backend that mounts this volume so
# verification follows the active deployment instead of the release path.
while IFS= read -r container_id; do
  [[ -n "$container_id" ]] || continue
  mounted_volume="$(docker inspect -f '{{ range .Mounts }}{{ if eq .Destination "/app/data" }}{{ .Name }}{{ end }}{{ end }}' "$container_id" 2>/dev/null || true)"
  [[ "$mounted_volume" == "$volume_name" ]] || continue
  runtime_project="$(docker inspect -f '{{ index .Config.Labels "com.docker.compose.project" }}' "$container_id" 2>/dev/null || true)"
  [[ -n "$runtime_project" ]] && break
done < <(docker ps -aq --filter 'label=com.docker.compose.service=backend')

if [[ -z "$compose_project" ]]; then
  compose_project="$(docker volume inspect -f '{{ index .Labels "com.docker.compose.project" }}' "$volume_name" 2>/dev/null || true)"
fi
if [[ -z "$compose_project" && "$volume_name" == *_backend-data ]]; then
  compose_project="${volume_name%_backend-data}"
fi
if [[ -n "$runtime_project" && "$runtime_project" != "$compose_project" ]]; then
  info "active backend uses Compose project $runtime_project (volume label suggested $compose_project)"
  compose_project="$runtime_project"
fi

echo "Zimphony Webmail update verification"
echo "Edition: $edition"
echo "Compose project: ${compose_project:-unknown}"
echo "Expected volume: $volume_name"
echo

if [[ -z "$compose_project" ]]; then
  fail "Compose project could not be identified"
else
  backend_id="$(docker compose -p "$compose_project" -f "$compose_file" ps -q backend 2>/dev/null || true)"
  frontend_id="$(docker compose -p "$compose_project" -f "$compose_file" ps -q frontend 2>/dev/null || true)"
  [[ -n "$backend_id" ]] && pass "backend container exists" || fail "backend container is missing"
  [[ -n "$frontend_id" ]] && pass "frontend container exists" || fail "frontend container is missing"

  backend_state="$(docker inspect -f '{{.State.Status}}' "$backend_id" 2>/dev/null || true)"
  frontend_state="$(docker inspect -f '{{.State.Status}}' "$frontend_id" 2>/dev/null || true)"
  [[ "$backend_state" == "running" ]] && pass "backend is running" || fail "backend is not running ($backend_state)"
  [[ "$frontend_state" == "running" ]] && pass "frontend is running" || fail "frontend is not running ($frontend_state)"

  mounted_volume="$(docker inspect -f '{{ range .Mounts }}{{ if eq .Destination "/app/data" }}{{ .Name }}{{ end }}{{ end }}' "$backend_id" 2>/dev/null || true)"
  [[ "$mounted_volume" == "$volume_name" ]] && pass "backend uses the original backend-data volume" || fail "backend volume is $mounted_volume, expected $volume_name"

  google_state="$(docker compose -p "$compose_project" -f "$compose_file" exec -T backend sh -lc '
    for name in google_tokens.json google_task_colors.json google_calendar_watches.json; do
      [ -s "/app/data/$name" ] && printf "%s\n" "$name"
    done
  ' 2>/dev/null || true)"
  if [[ -n "$google_state" ]]; then
    pass "Google runtime state files are present in backend-data"
  else
    info "Google runtime state files are not present in backend-data"
  fi
fi

[[ -f "$root_dir/deploy/docker/$edition/backend.env" ]] && pass "backend.env exists" || fail "backend.env is missing"
[[ -f "$root_dir/deploy/docker/$edition/frontend.env" ]] && pass "frontend.env exists" || fail "frontend.env is missing"

latest_backup="$(find "$base_dir/backups" -maxdepth 1 -type d -name "update-${edition}-*" -printf '%T@ %p\n' 2>/dev/null | sort -nr | awk 'NR==1 {$1=""; sub(/^ /, ""); print}')"
if [[ -n "$latest_backup" && -f "$latest_backup/backend.env" && -f "$latest_backup/frontend.env" ]]; then
  cmp -s "$latest_backup/backend.env" "$root_dir/deploy/docker/$edition/backend.env" \
    && pass "backend.env preserved" || fail "backend.env differs from update backup"
  cmp -s "$latest_backup/frontend.env" "$root_dir/deploy/docker/$edition/frontend.env" \
    && pass "frontend.env preserved" || fail "frontend.env differs from update backup"
else
  fail "update backup was not found"
fi

echo
if [[ "$failures" == "0" ]]; then
  echo "VERIFICATION PASSED"
  echo "Next: open the normal webmail URL and test login, mail, and enabled add-on features."
  exit 0
fi
echo "VERIFICATION FAILED ($failures check(s))"
echo "Inspect logs with: docker compose -p $compose_project -f $compose_file logs --tail=100 backend frontend"
exit 1
