#!/usr/bin/env bash

# Every service in the catalog has the same shape, because panama-server and
# the update timer both depend on it blindly:
#
#   * a compose.yml, which is the only file enable symlinks into ~/Server
#   * exactly one podman-*.service unit -- its filename is the unit's
#     identity, so two would be an ambiguity and zero an unenableable service
#   * a WorkingDirectory of %h/Server/<Name>, matching the directory enable
#     creates -- a unit pointing anywhere else starts compose against a
#     directory that has no .env and no data
#   * every ${VAR} the compose interpolates without a default is named in
#     .env.example, or the first enable renders a compose full of empty
#     strings and the service runs misconfigured rather than failing

set -uo pipefail

repo_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
containers_dir="$repo_dir/server/containers"

findings=()
note() { findings+=("$1"); }

[[ -d "$containers_dir" ]] || { printf 'containers shape contract: PASS (no services yet)\n'; exit 0; }

shopt -s nullglob
for dir in "$containers_dir"/*/; do
    name="$(basename "$dir")"

    [[ -f "$dir/compose.yml" ]] || note "$name has no compose.yml"

    units=("$dir"/*.service)
    if (( ${#units[@]} == 0 )); then
        note "$name has no unit file"
        continue
    elif (( ${#units[@]} > 1 )); then
        note "$name has ${#units[@]} unit files; its identity is ambiguous"
        continue
    fi
    unit="${units[0]}"

    case "$(basename "$unit")" in
        podman-*.service) ;;
        *) note "$name's unit is not named podman-<name>.service: $(basename "$unit")" ;;
    esac

    grep -q "^WorkingDirectory=%h/Server/$name\$" "$unit" \
        || note "$name's unit does not work in %h/Server/$name"
    grep -q 'podman compose' "$unit" \
        || note "$name's unit does not run podman compose"

    # ${VAR} without a :- default has nowhere to come from but the .env, and
    # the .env is seeded from .env.example -- so a variable the example does
    # not name is one the first enable silently renders empty.
    [[ -f "$dir/compose.yml" ]] || continue
    while IFS= read -r var; do
        [[ -n "$var" ]] || continue
        if [[ ! -f "$dir/.env.example" ]]; then
            note "$name interpolates \${$var} but has no .env.example"
            continue
        fi
        grep -qE "^${var}=" "$dir/.env.example" \
            || note "$name interpolates \${$var}, which .env.example does not name"
    done < <(grep -vE '^[[:space:]]*#' "$dir/compose.yml" 2>/dev/null \
        | grep -oE '\$\{[A-Za-z_][A-Za-z0-9_]*\}' \
        | sed 's/^\${//; s/}$//' | sort -u)
done

if (( ${#findings[@]} > 0 )); then
    mapfile -t findings < <(printf '%s\n' "${findings[@]}" | sort -u)
    printf 'containers shape contract: %d finding(s)\n' "${#findings[@]}" >&2
    printf '  - %s\n' "${findings[@]}" >&2
    exit 1
fi

printf 'containers shape contract: PASS\n'
