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

# Local services start RocketMQ consumers before any business event is produced,
# so relying on producer-side auto topic creation makes a fresh broker fail at
# startup. Keep the fixed owner-outbox topics explicit and idempotent here.
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"

cd "${PROJECT_ROOT}"

"${SCRIPT_DIR}/prepare-local-rocketmq-config.sh" >/dev/null
export ROCKETMQ_BROKER_CONFIG="${PROJECT_ROOT}/tmp/rocketmq/broker.local.conf"
"${SCRIPT_DIR}/resolve-compose-container-conflicts.sh" rocketmq-namesrv rocketmq-broker
running_services="$(docker compose ps --services --status running 2>/dev/null || true)"
namesrv_was_running=0
broker_was_running=0
if grep -qx "rocketmq-namesrv" <<<"${running_services}"; then
	namesrv_was_running=1
else
	docker compose up -d rocketmq-namesrv >/dev/null
fi
if grep -qx "rocketmq-broker" <<<"${running_services}"; then
	broker_was_running=1
fi

# `make run` is invoked repeatedly during local development. Recreating the
# broker on every run forces RocketMQ through store recovery, broker
# registration, and route propagation even when the same container is already
# healthy. Keep the existing broker hot by default, and reserve a forced
# recreate for explicit config refreshes via ROCKETMQ_FORCE_RECREATE=1.
if [[ "${ROCKETMQ_FORCE_RECREATE:-0}" == "1" ]]; then
	docker compose up -d --force-recreate rocketmq-broker >/dev/null
	broker_was_running=0
elif [[ "${broker_was_running}" != "1" ]]; then
	docker compose up -d rocketmq-broker >/dev/null
fi

MQADMIN="/home/rocketmq/rocketmq-5.3.1/bin/mqadmin"
NAMESRV="rocketmq-namesrv:9876"
CLUSTER="hyapp-local"
TOPIC_STAMP="${PROJECT_ROOT}/tmp/rocketmq/topics.applied"
TOPICS=(
	"hyapp_wallet_outbox"
	"hyapp_wallet_realtime_outbox"
	"hyapp_room_outbox"
	"hyapp_lucky_gift_outbox"
	"hyapp_room_rocket_launch"
	"hyapp_user_outbox"
	"hyapp_message_action_outbox"
	"hyapp_activity_outbox"
	"hyapp_game_outbox"
)

topic_fingerprint() {
	if command -v shasum >/dev/null 2>&1; then
		printf '%s\n' "${TOPICS[@]}" | shasum -a 256 | awk '{print $1}'
		return
	fi
	printf '%s\n' "${TOPICS[@]}" | sha256sum | awk '{print $1}'
}

write_topic_stamp() {
	local broker_container_id="$1"
	local fingerprint="$2"

	# The stamp is only a local startup accelerator. It is scoped to the Docker
	# container id plus the exact topic list, so replacing the broker or adding a
	# new owner-outbox topic automatically falls back to mqadmin verification.
	{
		printf 'broker_container_id=%s\n' "${broker_container_id}"
		printf 'topics_sha256=%s\n' "${fingerprint}"
		for topic in "${TOPICS[@]}"; do
			printf 'topic=%s\n' "${topic}"
		done
	} >"${TOPIC_STAMP}"
}

broker_container_id="$(docker compose ps -q rocketmq-broker)"
topics_sha256="$(topic_fingerprint)"
if [[ "${namesrv_was_running}" == "1" && "${broker_was_running}" == "1" && -n "${broker_container_id}" && -f "${TOPIC_STAMP}" ]]; then
	if grep -Fxq "broker_container_id=${broker_container_id}" "${TOPIC_STAMP}" && grep -Fxq "topics_sha256=${topics_sha256}" "${TOPIC_STAMP}"; then
		printf 'rocketmq topics already applied\n'
		exit 0
	fi
fi

# The broker process can accept a container start before it has registered with
# NameServer. Wait for the cluster view so topic checks and updateTopic target
# the real broker instead of racing the route table.
cluster_view=""
for _ in {1..60}; do
	if cluster_view="$(docker compose exec -T rocketmq-broker "${MQADMIN}" clusterList -n "${NAMESRV}" 2>/dev/null)" && grep -q "${CLUSTER}" <<<"${cluster_view}"; then
		break
	fi

	sleep 1
done

if ! grep -q "${CLUSTER}" <<<"${cluster_view}"; then
	printf 'rocketmq broker did not register in cluster %s before topic init\n' "${CLUSTER}" >&2
	exit 1
fi

# Topic creation is idempotent, but each updateTopic call shells into the
# broker container and blocks local startup. Query once and only create missing
# topics; a warm `make run` then pays one cheap route read instead of repeating
# management writes for the full fixed topic set.
topic_list="$(docker compose exec -T rocketmq-broker "${MQADMIN}" topicList -n "${NAMESRV}" 2>/dev/null || true)"
missing_topics=()
for topic in "${TOPICS[@]}"; do
	if grep -Fxq "${topic}" <<<"${topic_list}"; then
		continue
	fi
	missing_topics+=("${topic}")
done

if [[ ${#missing_topics[@]} -eq 0 ]]; then
	write_topic_stamp "${broker_container_id}" "${topics_sha256}"
	printf 'rocketmq topics already applied\n'
	exit 0
fi

for topic in "${missing_topics[@]}"; do
	printf 'applying rocketmq topic: %s\n' "${topic}"
	docker compose exec -T rocketmq-broker "${MQADMIN}" updateTopic -n "${NAMESRV}" -c "${CLUSTER}" -t "${topic}" -r 8 -w 8 >/dev/null
done
write_topic_stamp "${broker_container_id}" "${topics_sha256}"
