#!/usr/bin/env bash

# The opencode config, generated rather than linked.
#
# Every other personal destination is a symlink or a one-time copy, so getting
# one wrong is visible and cheap to undo. This one is written whole by
# setup/scripts/link-mcp, and it is the only file in the set that carries
# secrets -- which is the reason it is generated at all. Three properties are
# worth pinning:
#
#   1. The tracked template is the source of truth and holds no secret. It is
#      readable by anyone who finds the repository, so a token in it is a
#      disclosure rather than a mistake.
#   2. The generation is faithful: the template's keys survive, the MCP block
#      appears, and a leading ~/ is resolved so the output is readable.
#   3. Nothing is destroyed and nothing churns. A file somebody wrote by hand
#      goes to config/old/, and running the stage again does not fill it up.

set -uo pipefail

repo_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
linker="$repo_dir/setup/scripts/link-mcp"
template="$repo_dir/user/agents/opencode/config.json"
servers="$repo_dir/user/agents/mcp/servers"

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

[[ -x "$linker" ]] || { printf 'opencode config contract: %s is not executable\n' "$linker" >&2; exit 1; }

# ── 1. The template holds no secret ──────────────────────────────────────────

if [[ ! -r "$template" ]]; then
    note 'user/agents/opencode/config.json is missing, so nothing generates an opencode config'
else
    jq -e . "$template" >/dev/null 2>&1 \
        || note 'user/agents/opencode/config.json is not valid JSON'

    if grep -qE 'BEGIN [A-Z ]*PRIVATE KEY|sk-ant-[A-Za-z0-9]|ghp_[A-Za-z0-9]{20}|xox[baprs]-[A-Za-z0-9]' "$template" 2>/dev/null; then
        note 'user/agents/opencode/config.json carries something that looks like a token'
    fi
fi

[[ -r "$servers" ]] || note 'user/agents/mcp/servers is missing, so no MCP servers can be registered'

# ── 2 and 3, against a throwaway home ────────────────────────────────────────

work="$(mktemp -d)"
trap 'rm -rf "$work"' EXIT

checkout="$work/Panama"
mkdir -p "$checkout/setup/scripts" "$checkout/user/agents/mcp/bin" "$checkout/user/agents/opencode"
cp "$linker" "$checkout/setup/scripts/link-mcp"
cp "$template" "$checkout/user/agents/opencode/config.json"
printf '#!/usr/bin/env bash\nexit 0\n' >"$checkout/user/agents/mcp/bin/gamma"
chmod +x "$checkout/user/agents/mcp/bin/gamma"
cat >"$checkout/user/agents/mcp/servers" <<'FIXTURE'
# a comment, then a row that needs a token, one that needs none, and a stdio one

alpha  http  https://alpha.example/mcp  ALPHA_TOKEN
beta   http  https://beta.example/mcp
gamma  stdio  bin/gamma
FIXTURE
printf 'ALPHA_TOKEN=sekrit-token-value\n' >"$checkout/user/agents/mcp/env"

# link-mcp registers through whichever runtime it finds, and gives up entirely
# when it finds neither. A stub is enough to prove the config generation.
mkdir -p "$work/bin"
printf '#!/usr/bin/env bash\nexit 0\n' >"$work/bin/opencode"
chmod +x "$work/bin/opencode"

home="$work/home"
state="$work/state"
old="$checkout/config/old"
# Every XDG directory is pinned to the throwaway home. XDG_CONFIG_HOME is
# usually set in the environment this runs from, and leaving it alone would send
# the generated config at the real ~/.config/opencode rather than at the fixture.
mkdir -p "$home/.config/opencode" "$state/panama"

run() {
    HOME="$home" XDG_CONFIG_HOME="$home/.config" XDG_STATE_HOME="$state" \
        PANAMA_PATH="$checkout" PATH="$work/bin:$PATH" \
        "$checkout/setup/scripts/link-mcp" >"$work/log" 2>&1
}

generated="$home/.config/opencode/opencode.jsonc"

# A file somebody wrote by hand is there before this stage ever runs.
printf '{"model": "someone-elses-hand-edit"}\n' >"$generated"

printf 'yes\n' >"$state/panama/user-content"
if ! run; then
    note "link-mcp failed against a throwaway home: $(tail -1 "$work/log")"
fi

# ── The hand-edit is preserved, not deleted ──────────────────────────────────

if ! grep -rq 'someone-elses-hand-edit' "$old" 2>/dev/null; then
    note 'a config written by hand was not preserved in config/old/'
fi

# ── The generation is faithful ───────────────────────────────────────────────

body="$(sed '/^\/\//d' "$generated" 2>/dev/null)"

jq -e . <<<"$body" >/dev/null 2>&1 \
    || note 'the generated opencode config is not valid JSON once its header comment is stripped'
grep -qF 'generated by setup/scripts/link-mcp' "$generated" 2>/dev/null \
    || note 'the generated opencode config does not say who wrote it or where to edit instead'

if ! jq -e --arg home "$home" '.instructions | index($home + "/.claude/rules/*.md")' <<<"$body" >/dev/null 2>&1; then
    note 'the generated opencode config did not resolve the ~/ rules path to this home'
fi
jq -e '.permissions | length > 0' <<<"$body" >/dev/null 2>&1 \
    || note 'the template permissions did not reach the generated opencode config'

jq -e '.mcp.alpha.headers.Authorization == "sekrit-token-value"' <<<"$body" >/dev/null 2>&1 \
    || note 'a token-carrying server was registered without its Authorization header'
jq -e '.mcp.beta | has("headers") | not' <<<"$body" >/dev/null 2>&1 \
    || note 'a server that needs no token was given a header anyway'
jq -e --arg launcher "$checkout/user/agents/mcp/bin/gamma" '.mcp.gamma.command == [$launcher]' <<<"$body" >/dev/null 2>&1 \
    || note 'a stdio server was not registered against its launcher in this checkout'

# The file holds tokens, so it is private. Checked on the file rather than on
# the umask, because the umask is not what a later reader sees.
mode="$(stat -c '%a' "$generated" 2>/dev/null)"
[[ "$mode" == 600 ]] || note "the generated opencode config is mode $mode, not 600"

# The template is readable by anybody who finds the repository. The tokens live
# in the generated file and in user/agents/mcp/env, never here.
if grep -qF 'sekrit-token-value' "$template" 2>/dev/null; then
    note 'the tracked opencode template carries an MCP token'
fi

# ── Re-running replaces, and does not churn ──────────────────────────────────

before="$(find "$old" -type f 2>/dev/null | wc -l)"
run
after="$(find "$old" -type f 2>/dev/null | wc -l)"
[[ "$before" == "$after" ]] \
    || note 're-running link-mcp buried its own output in config/old/, so it grows every upgrade'
grep -qF 'generated by setup/scripts/link-mcp' "$generated" 2>/dev/null \
    || note 're-running link-mcp did not rewrite the config it generates'

# A machine that never said yes is left alone, the same gate every other
# personal destination obeys.
rm -f "$generated"
printf 'no\n' >"$state/panama/user-content"
run
[[ ! -e "$generated" ]] \
    || note 'an opencode config was generated on a machine that never said yes'

if (( ${#findings[@]} > 0 )); then
    printf 'opencode config contract: %d finding(s)\n' "${#findings[@]}" >&2
    printf '  - %s\n' "${findings[@]}" >&2
    exit 1
fi

printf 'opencode config contract: PASS\n'
