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

# Docker Compose cannot reuse a fixed `container_name` that is already owned by
# another compose project. Local development often leaves those containers behind
# after moving or renaming the repo, so remove only compose-owned stale conflicts
# before `docker compose up` reaches Docker's generic name-conflict failure.
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"

cd "${PROJECT_ROOT}"

if ! command -v python3 >/dev/null 2>&1; then
	printf 'python3 is required to inspect docker compose config before startup\n' >&2
	exit 1
fi

compose_config="$(docker compose config --format json)"
compose_project="$(printf '%s' "${compose_config}" | python3 -c 'import json, sys; print(json.load(sys.stdin).get("name", ""))')"
if [[ -z "${compose_project}" ]]; then
	printf 'docker compose project name is empty; cannot resolve container conflicts safely\n' >&2
	exit 1
fi

spec_file="$(mktemp)"
trap 'rm -f "${spec_file}"' EXIT

printf '%s' "${compose_config}" | python3 -c 'import json, sys
config = json.load(sys.stdin)
for service_name, service in sorted(config.get("services", {}).items()):
    container_name = service.get("container_name")
    if container_name:
        print(f"{service_name}\t{container_name}")
' > "${spec_file}"

for requested_service in "$@"; do
	if ! awk -F '\t' -v service="${requested_service}" '$1 == service { found = 1 } END { exit !found }' "${spec_file}"; then
		printf 'unknown compose service for conflict resolution: %s\n' "${requested_service}" >&2
		exit 1
	fi
done

docker_label() {
	local container_name="$1"
	local label_name="$2"

	docker inspect --format "{{ with index .Config.Labels \"${label_name}\" }}{{ . }}{{ end }}" "${container_name}" 2>/dev/null || true
}

requested_services=" $* "

while IFS=$'\t' read -r service_name container_name; do
	if [[ -z "${service_name}" || -z "${container_name}" ]]; then
		continue
	fi

	if [[ "$#" -gt 0 && "${requested_services}" != *" ${service_name} "* ]]; then
		continue
	fi

	container_id="$(docker inspect --format '{{.Id}}' "${container_name}" 2>/dev/null || true)"
	if [[ -z "${container_id}" ]]; then
		continue
	fi

	label_project="$(docker_label "${container_name}" "com.docker.compose.project")"
	label_service="$(docker_label "${container_name}" "com.docker.compose.service")"
	label_workdir="$(docker_label "${container_name}" "com.docker.compose.project.working_dir")"
	label_config_files="$(docker_label "${container_name}" "com.docker.compose.project.config_files")"

	# A container created by this exact compose project can be reused by compose;
	# deleting it would discard useful local process state without fixing anything.
	if [[ "${label_project}" == "${compose_project}" ]] && \
		{ [[ "${label_workdir}" == "${PROJECT_ROOT}" ]] || [[ "${label_config_files}" == *"${PROJECT_ROOT}/"* ]]; }; then
		continue
	fi

	# Manual or unlabeled containers have unknown ownership. Fail with a precise
	# command instead of guessing that this repo is allowed to remove them.
	if [[ -z "${label_project}" || -z "${label_service}" ]]; then
		printf 'container name conflict: %s (%s) is not managed by Docker Compose\n' "${container_name}" "${container_id:0:12}" >&2
		printf 'remove or rename it before startup, for example: docker rm -f %s\n' "${container_name}" >&2
		exit 1
	fi

	printf 'removing stale compose container: %s (%s, project=%s, service=%s, working_dir=%s)\n' \
		"${container_name}" "${container_id:0:12}" "${label_project}" "${label_service}" "${label_workdir:-unknown}"
	docker rm -f "${container_name}" >/dev/null
done < "${spec_file}"
