#!/usr/bin/env python3
"""echo_output.py — M4: machine-readable output + dry-run plumbing.  [v1.0 SCAFFOLD — implemented]

The high-level ops (capture/recall/resolve/scope) print prose, forcing the agent to
re-parse free text to act on a result. This provides a single JSON envelope and a
small dry-run helper so every op can emit a structured result and preview writes.

INTEGRATION (merge step): thread a global `--json` / `--dry-run` flag through echo.py's
parser and have each cmd_* return its data dict; emit() it. In --dry-run, the write
verbs print the envelope with action="dry-run" and perform no network mutation.
"""
from __future__ import annotations

import json
import sys


def envelope(action: str, data: dict | None = None, ok: bool = True,
             error: str | None = None) -> dict:
    """Canonical result shape for every high-level op."""
    env = {"ok": ok, "action": action}
    if data:
        env.update(data)
    if error:
        env["error"] = error
    return env


def emit(env: dict, as_json: bool) -> None:
    """Print either the JSON envelope (machine mode) or a one-line human summary."""
    if as_json:
        print(json.dumps(env, ensure_ascii=False))
        return
    if not env.get("ok"):
        print(f"error: {env.get('error', 'failed')}", file=sys.stderr)
        return
    bits = [env.get("action", "ok")]
    if env.get("path"):
        bits.append(str(env["path"]))
    if env.get("links_added"):
        bits.append(f"+{env['links_added']} links")
    print("ok: " + " ".join(bits))


def dry_run_envelope(action: str, data: dict | None = None) -> dict:
    """Result for a previewed-but-not-executed write."""
    return envelope(f"dry-run:{action}", data, ok=True)
