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

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"

DOCKER_CMD=()
SECRETS_FILE="$SCRIPT_DIR/.mongo-secrets.env"
RESET_MONGO_DATA=0

for arg in "$@"; do
	case "$arg" in
		--reset-mongo-data|-r)
			RESET_MONGO_DATA=1
			;;
	esac
done

ensure_mongo_secrets() {
	if [ -f "$SECRETS_FILE" ]; then
		# shellcheck disable=SC1090
		source "$SECRETS_FILE"
	fi

	if [ -z "${MONGO_INITDB_ROOT_PASSWORD:-}" ]; then
		MONGO_INITDB_ROOT_PASSWORD="$(openssl rand -hex 24)"
	fi
	if [ -z "${MONGO_APP_PASSWORD:-}" ]; then
		MONGO_APP_PASSWORD="$(openssl rand -hex 24)"
	fi

	cat > "$SECRETS_FILE" <<EOF
MONGO_INITDB_ROOT_USERNAME=${MONGO_INITDB_ROOT_USERNAME:-website_root}
MONGO_INITDB_ROOT_PASSWORD=$MONGO_INITDB_ROOT_PASSWORD
MONGO_APP_USER=${MONGO_APP_USER:-website_app}
MONGO_APP_PASSWORD=$MONGO_APP_PASSWORD
EOF
	chmod 600 "$SECRETS_FILE"
	# shellcheck disable=SC1090
	source "$SECRETS_FILE"
	export MONGO_INITDB_ROOT_USERNAME MONGO_INITDB_ROOT_PASSWORD MONGO_APP_USER MONGO_APP_PASSWORD
}

ensure_mongo_app_user() {
	if "${DOCKER_CMD[@]}" compose --env-file "$SECRETS_FILE" exec -T mongodb mongosh --quiet \
		--username "$MONGO_INITDB_ROOT_USERNAME" \
		--password "$MONGO_INITDB_ROOT_PASSWORD" \
		--authenticationDatabase admin \
		--eval '
const appDatabase = process.env.MONGO_DB_NAME || "Invario_Website";
const appUser = process.env.MONGO_APP_USER || "website_app";
const appPassword = process.env.MONGO_APP_PASSWORD;

if (!appPassword) {
	throw new Error("Missing MONGO_APP_PASSWORD");
}

const appDb = db.getSiblingDB(appDatabase);
if (!appDb.getUser(appUser)) {
	appDb.createUser({
		user: appUser,
		pwd: appPassword,
		roles: [{ role: "readWrite", db: appDatabase }],
	});
	print("created app user");
} else {
	appDb.updateUser(appUser, {
		pwd: appPassword,
		roles: [{ role: "readWrite", db: appDatabase }],
	});
	print("updated app user");
}
'
	then
		return 0
	fi

	echo "[WARNUNG] App-User konnte nicht synchronisiert werden; der bestehende Mongo-Volume-Stand verwendet wahrscheinlich andere Root-Credentials. Falls das ein frischer Dev-Stand ist, starte mit MONGO_RESET_DATA=1 neu." >&2
	return 0
}

wait_for_mongo_ready() {
	local timeout_seconds=180
	local interval=2
	local elapsed=0
	local mongo_container_id=""
	local container_state=""
	local health_status=""

	mongo_container_id="$("${DOCKER_CMD[@]}" compose --env-file "$SECRETS_FILE" ps -q mongodb 2>/dev/null || true)"
	if [ -z "$mongo_container_id" ]; then
		echo "[FEHLER] MongoDB-Container wurde nicht gefunden." >&2
		return 1
	fi

	while [ $elapsed -lt $timeout_seconds ]; do
		container_state="$(${DOCKER_CMD[@]} inspect -f '{{.State.Status}} {{if .State.Health}}{{.State.Health.Status}}{{end}}' "$mongo_container_id" 2>/dev/null || true)"
		health_status="${container_state#* }"
		if [ "$health_status" = "healthy" ]; then
			return 0
		fi
		if [ "${container_state%% *}" = "running" ] && [ -z "$health_status" ]; then
			return 0
		fi
		if [ "${container_state%% *}" = "exited" ] || [ "${container_state%% *}" = "dead" ]; then
			break
		fi
		sleep $interval
		elapsed=$((elapsed + interval))
	done

	echo "[FEHLER] MongoDB wurde nicht rechtzeitig gestartet. Status: ${container_state:-unbekannt}" >&2
	"${DOCKER_CMD[@]}" compose --env-file "$SECRETS_FILE" ps mongodb >&2 || true
	"${DOCKER_CMD[@]}" compose --env-file "$SECRETS_FILE" logs --tail 80 mongodb >&2 || true
	return 1
}

resolve_docker_cmd() {
	if docker info >/dev/null 2>&1; then
		DOCKER_CMD=(docker)
		return 0
	fi

	if sudo -n docker info >/dev/null 2>&1; then
		DOCKER_CMD=(sudo docker)
		return 0
	fi

	if command -v sudo >/dev/null 2>&1 && [ -t 0 ]; then
		echo "Docker-Zugriff ohne Gruppe erkannt. Verwende sudo docker (ggf. Passwortabfrage)."
		if sudo docker info >/dev/null 2>&1; then
			DOCKER_CMD=(sudo docker)
			return 0
		fi
	fi

	echo "[FEHLER] Kein Zugriff auf den Docker Daemon (/var/run/docker.sock)." >&2
	echo "Führe das Script mit sudo aus oder füge deinen User zur docker-Gruppe hinzu:" >&2
	echo "  sudo usermod -aG docker $USER" >&2
	echo "Danach neu einloggen und Script erneut starten." >&2
	exit 3
}

compose() {
	"${DOCKER_CMD[@]}" compose --env-file "$SECRETS_FILE" "$@"
}

is_truthy() {
	case "${1:-}" in
		1|true|TRUE|yes|YES|on|ON)
			return 0
			;;
		*)
			return 1
			;;
	esac
}

reset_mongo_data_if_requested() {
	if ! is_truthy "${MONGO_RESET_DATA:-0}" && [ "$RESET_MONGO_DATA" -ne 1 ]; then
		return 0
	fi

	echo "[WARNUNG] Setze den MongoDB-Volume-Stand zurück, damit die aktuellen Secrets neu initialisiert werden." >&2
	"${DOCKER_CMD[@]}" compose --env-file "$SECRETS_FILE" down -v --remove-orphans
}

build_website_image() {
	if compose build website; then
		return 0
	fi

	echo "[WARNUNG] Standard-Build fehlgeschlagen, versuche Legacy-Build ohne BuildKit erneut..." >&2
	DOCKER_BUILDKIT=0 COMPOSE_DOCKER_CLI_BUILD=0 compose build website
}

export SESSION_COOKIE_SECURE="0"
export INSTANCE_TLS_MODE="development"
export INSTANCE_PARENT_DOMAIN="${INSTANCE_PARENT_DOMAIN:-meine-domain}"
export DEV_HOSTS_REFRESH_INTERVAL="${DEV_HOSTS_REFRESH_INTERVAL:-30}"

echo "Launching WEBSITE stack"
echo "  SESSION_COOKIE_SECURE=$SESSION_COOKIE_SECURE"
echo "  INSTANCE_TLS_MODE=$INSTANCE_TLS_MODE"
echo "  INSTANCE_PARENT_DOMAIN=$INSTANCE_PARENT_DOMAIN"
echo "  DEV_HOSTS_REFRESH_INTERVAL=$DEV_HOSTS_REFRESH_INTERVAL"

ensure_mongo_secrets

# Ensure required runtime files exist before building
if [ ! -f "$SCRIPT_DIR/gunicorn.conf.py" ]; then
	echo "[FEHLER] gunicorn.conf.py fehlt in $SCRIPT_DIR. Bitte prüfen." >&2
	exit 2
fi

resolve_docker_cmd

reset_mongo_data_if_requested

build_website_image
compose up -d mongodb
wait_for_mongo_ready
ensure_mongo_app_user
compose up -d --no-deps website

# Wait for website to become healthy (simple HTTP check)
check_url="http://localhost:4999"
timeout_seconds=60
interval=2
elapsed=0

echo "Warte auf Website (${check_url}) bis ${timeout_seconds}s..."
while [ $elapsed -lt $timeout_seconds ]; do
	if curl -sS --max-time 2 "$check_url" >/dev/null 2>&1; then
		echo "Website erreichbar nach ${elapsed}s"
		break
	fi
	sleep $interval
	elapsed=$((elapsed + interval))
done

if [ $elapsed -ge $timeout_seconds ]; then
	echo "[FEHLER] Website nicht erreichbar nach ${timeout_seconds}s. Sammle Diagnosedaten..."
	echo "--- docker compose ps ---"
		compose ps || true
	echo "--- docker logs website (tail 200) ---"
	"${DOCKER_CMD[@]}" logs --tail 200 website-website-1 || true
	echo "Bitte prüfe Container-Logs und nginx-Konfiguration."
fi

echo "Website stack is running on http://localhost:4999"
echo "Provisioning creates self-signed certs per subdomain when needed."