#!/bin/sh
# migrate-toplevel-peers.sh — migrate a ZDDC root from the old
# "everything under archive/<party>/" layout to the flat top-level
# party-peer layout.
#
# Per project (a top-level dir containing archive/), for each
# archive/<party>/:
#   - move archive/<party>/{incoming,working,staging,reviewing,mdl,rsk}
#       → <project>/<slot>/<party>/   (the workspace/register peers)
#   - move archive/<party>/ssr.yaml   → <project>/ssr/<party>.yaml
#       (this establishes the party registry — a party exists iff its
#        ssr/<party>.yaml exists)
#   - if a party has no ssr.yaml, synthesize a minimal ssr/<party>.yaml
#       so it stays registered (else its workspaces can't be recreated)
#   - LEAVE archive/<party>/{received,issued} in place (the WORM record)
#
# Then, tree-wide, relocate any table.yaml / form.yaml config out of a
# directory root and into that directory's .zddc.d/ reserve (where the
# server now resolves specs from; the legacy root location still works, so
# this is a declutter, not a hard requirement).
#
# Per-folder .zddc files travel with their directory (the whole slot dir
# is moved). Idempotent: already-migrated paths are skipped. Run with the
# server stopped (or accept it's a plain filesystem move).
#
# Usage:
#   migrate-toplevel-peers.sh [--dry-run] <ZDDC_ROOT>
#
# --dry-run prints what would happen and changes nothing.

set -eu

DRY=0
ROOT=""
for arg in "$@"; do
	case "$arg" in
	--dry-run) DRY=1 ;;
	-h|--help)
		sed -n '2,30p' "$0" | sed 's/^# \{0,1\}//'
		exit 0
		;;
	-*)
		echo "unknown flag: $arg" >&2
		exit 2
		;;
	*) ROOT="$arg" ;;
	esac
done

if [ -z "$ROOT" ] || [ ! -d "$ROOT" ]; then
	echo "usage: $0 [--dry-run] <ZDDC_ROOT>" >&2
	exit 2
fi

WORKSPACE_SLOTS="incoming working staging reviewing mdl rsk"
moved=0
synth=0
skipped=0

say() { printf '%s\n' "$*"; }
act() {
	# act <description> <command...>
	desc=$1
	shift
	if [ "$DRY" -eq 1 ]; then
		say "DRY  $desc"
	else
		say "  -> $desc"
		"$@"
	fi
}

# move_dir SRC DST — move a directory, creating DST's parent. Skips when
# SRC is absent (nothing to do) or DST already exists (already migrated).
move_dir() {
	src=$1
	dst=$2
	[ -d "$src" ] || return 0
	if [ -e "$dst" ]; then
		say "  .. skip (dest exists): $dst"
		skipped=$((skipped + 1))
		return 0
	fi
	parent=$(dirname "$dst")
	act "mkdir -p $parent" mkdir -p "$parent"
	act "mv $src -> $dst" mv "$src" "$dst"
	moved=$((moved + 1))
}

# move_file SRC DST — same shape, for the ssr.yaml registry row.
move_file() {
	src=$1
	dst=$2
	[ -f "$src" ] || return 0
	if [ -e "$dst" ]; then
		say "  .. skip (dest exists): $dst"
		skipped=$((skipped + 1))
		return 0
	fi
	parent=$(dirname "$dst")
	act "mkdir -p $parent" mkdir -p "$parent"
	act "mv $src -> $dst" mv "$src" "$dst"
	moved=$((moved + 1))
}

synth_registry() {
	dst=$1
	[ -e "$dst" ] && return 0
	parent=$(dirname "$dst")
	act "mkdir -p $parent" mkdir -p "$parent"
	if [ "$DRY" -eq 1 ]; then
		say "DRY  synthesize $dst (kind: SSR)"
	else
		say "  -> synthesize $dst (kind: SSR)"
		printf 'kind: SSR\n' >"$dst"
	fi
	synth=$((synth + 1))
}

# relocate_configs — move every <dir>/table.yaml and <dir>/form.yaml into
# <dir>/.zddc.d/. Tree-wide; skips files already under a .zddc.d/ and any
# destination that already exists. Uses find | while-read so directory names
# with spaces are handled (counters live in the subshell, so this pass just
# logs its actions rather than feeding the summary).
relocate_configs() {
	find "$ROOT" -type f \( -name table.yaml -o -name form.yaml \) 2>/dev/null | while IFS= read -r f; do
		case "$f" in
		*/.zddc.d/*) continue ;;
		esac
		d=$(dirname "$f")
		base=$(basename "$f")
		dst="$d/.zddc.d/$base"
		if [ -e "$dst" ]; then
			say "  .. skip (dest exists): $dst"
			continue
		fi
		act "mkdir -p $d/.zddc.d" mkdir -p "$d/.zddc.d"
		act "mv $f -> $dst" mv "$f" "$dst"
	done
}

for projectdir in "$ROOT"/*/; do
	[ -d "$projectdir/archive" ] || continue
	project=$(basename "$projectdir")
	case "$project" in .* | _*) continue ;; esac

	say "project: $project"
	for partydir in "$projectdir"archive/*/; do
		[ -d "$partydir" ] || continue
		party=$(basename "$partydir")
		case "$party" in .* | _*) continue ;; esac
		say " party: $party"

		# 1. Registry row: archive/<party>/ssr.yaml -> ssr/<party>.yaml
		move_file "${partydir}ssr.yaml" "${projectdir}ssr/${party}.yaml"

		# 2. Workspace/register slots -> <slot>/<party>/
		for slot in $WORKSPACE_SLOTS; do
			move_dir "${partydir}${slot}" "${projectdir}${slot}/${party}"
		done

		# 3. Guarantee a registry entry so the party stays registered.
		synth_registry "${projectdir}ssr/${party}.yaml"
	done
done

# Tree-wide config relocation (runs over the now-migrated layout).
say ""
say "relocating table.yaml/form.yaml configs into .zddc.d/ …"
relocate_configs

say ""
say "summary: moved=$moved synthesized=$synth skipped=$skipped"
[ "$DRY" -eq 1 ] && say "(dry-run — nothing changed)"
exit 0
