"""Tests for ``mgf-common sync-prompt``.

The subcommand prints the federation sync/conformance prompt (the body the
``/sync`` slash command runs), resolved through
``mgf.standard.read_recipe("federation-sync-prompt")`` rather than a
hand-copied command body — so the single source of truth is the
``mgf-standard`` version the project pins. It degrades with an actionable
error if that seam is unavailable (``mgf-standard`` < 0.1.3).
"""

from __future__ import annotations

import argparse
import io
from contextlib import redirect_stderr, redirect_stdout

from mgf.common.cli._exit_codes import EXIT_SUCCESS, EXIT_UNKNOWN

from mgf.fed.cli import _sync_prompt
from mgf.fed.cli._sync_prompt import add_sync_prompt_args, run_sync_prompt


def _make_args() -> argparse.Namespace:
    return argparse.Namespace()


class TestRunSyncPrompt:
    def test_prints_recipe_and_returns_exit_ok(self) -> None:
        # mgf-standard (>=0.1.3) is a dependency, so the recipe resolves.
        buf = io.StringIO()
        with redirect_stdout(buf):
            rc = run_sync_prompt(_make_args())
        assert rc == EXIT_SUCCESS
        out = buf.getvalue()
        # A stable marker from the prompt body the recipe carries.
        assert "federation-conformance engineer" in out

    def test_output_ends_with_a_newline(self) -> None:
        buf = io.StringIO()
        with redirect_stdout(buf):
            run_sync_prompt(_make_args())
        assert buf.getvalue().endswith("\n")

    def test_unresolvable_recipe_errors_with_guidance(self, monkeypatch) -> None:
        # Simulate a missing mgf-standard corpus: the resolver returns
        # None, and the command must fail closed (non-zero, no partial prompt)
        # with a LOUD, actionable message naming the exact install (WU3).
        monkeypatch.setattr(_sync_prompt, "_resolve_recipe", lambda: None)
        out, err = io.StringIO(), io.StringIO()
        with redirect_stdout(out), redirect_stderr(err):
            rc = run_sync_prompt(_make_args())
        assert rc == EXIT_UNKNOWN
        assert out.getvalue() == ""  # never a partial prompt
        assert "mgf-common[standards]" in err.getvalue()


class TestResolveRecipe:
    def test_returns_the_prompt_text(self) -> None:
        text = _sync_prompt._resolve_recipe()
        assert text is not None
        assert "federation-conformance engineer" in text


class TestAddSyncPromptArgs:
    def test_accepts_a_subparser_without_raising(self) -> None:
        # Future-flag-friendly shape: register adds nothing today but MUST
        # not crash when called by the dispatcher.
        parser = argparse.ArgumentParser()
        add_sync_prompt_args(parser)
        ns = parser.parse_args([])
        assert isinstance(ns, argparse.Namespace)
