"""Helper script for tdd_plan_correct_plan_id.robot integration tests.

Each subcommand exercises the ``plan correct`` CLI command with a plan_id
as the first positional argument (where ``decision_id`` is expected).
The helper reports the **real** outcome: it exits 0 and prints the sentinel
when the operation succeeds (bug is fixed), and exits 1 when the bug is
still present.  The ``tdd_expected_fail_listener`` on the Robot side handles
pass/fail inversion while the bug remains open.

Bug: https://git.cleverthis.com/cleveragents/cleveragents-core/issues/969
TDD: https://git.cleverthis.com/cleveragents/cleveragents-core/issues/979
"""

from __future__ import annotations

import sys
from collections.abc import Callable
from pathlib import Path
from unittest.mock import patch

# Ensure local source tree is importable
_SRC = str(Path(__file__).resolve().parents[1] / "src")
if _SRC not in sys.path:
    sys.path.insert(0, _SRC)

# Ensure features package is importable for shared fixtures
_FEATURES = str(Path(__file__).resolve().parents[1])
if _FEATURES not in sys.path:
    sys.path.insert(0, _FEATURES)

from features.mocks.tdd_plan_correct_plan_id_fixtures import (  # noqa: E402
    PATCH_CONTAINER,
    PATCH_RESOLVE_PLAN,
    PLAN_ID,
    ROOT_DECISION_ID,
    build_cli_args,
    make_correction_svc,
    make_default_container,
)
from typer.testing import CliRunner  # noqa: E402

from cleveragents.cli.commands.plan import app as plan_app  # noqa: E402

runner = CliRunner()


# ---------------------------------------------------------------------------
# Subcommands
# ---------------------------------------------------------------------------


def _run_plan_correct(mode: str, sentinel: str) -> None:
    """Invoke ``plan correct <plan_id>`` and verify target_decision_id.

    Exits 0 with *sentinel* when the command correctly resolves the
    plan_id to the root decision (bug fixed).
    Exits 1 when the bug is still present.

    Args:
        mode: The correction mode (``"revert"`` or ``"append"``).
        sentinel: The sentinel string to print on success.
    """
    mock_container = make_default_container()
    correction_svc = make_correction_svc(ROOT_DECISION_ID, mode=mode)
    mock_container.correction_service.return_value = correction_svc

    args = build_cli_args(PLAN_ID, mode=mode)

    with (
        patch(PATCH_CONTAINER, return_value=mock_container),
        patch(PATCH_RESOLVE_PLAN, return_value=PLAN_ID),
    ):
        result = runner.invoke(plan_app, args)

    if result.exit_code != 0:
        print(
            f"plan correct failed with exit code {result.exit_code}: {result.output}",
            file=sys.stderr,
        )
        sys.exit(1)

    # Check that request_correction was called with root decision, not plan_id
    correction_svc.request_correction.assert_called_once()
    call_record = correction_svc.request_correction.call_args
    kw = call_record.kwargs

    actual_target = kw.get("target_decision_id")
    if actual_target != ROOT_DECISION_ID:
        print(
            f"Bug #969: request_correction called with "
            f"target_decision_id={actual_target!r}, expected "
            f"{ROOT_DECISION_ID!r}. Plan_id ({PLAN_ID!r}) was used "
            f"as decision_id instead of being resolved to root decision.",
            file=sys.stderr,
        )
        sys.exit(1)

    print(sentinel)


def plan_correct_with_plan_id() -> None:
    """Invoke ``plan correct <plan_id>`` with --mode revert."""
    _run_plan_correct("revert", "tdd-plan-correct-plan-id-ok")


def plan_correct_append_with_plan_id() -> None:
    """Invoke ``plan correct <plan_id>`` with --mode append."""
    _run_plan_correct("append", "tdd-plan-correct-plan-id-append-ok")


# ---------------------------------------------------------------------------
# Dispatcher
# ---------------------------------------------------------------------------

_COMMANDS: dict[str, Callable[[], None]] = {
    "plan-correct-with-plan-id": plan_correct_with_plan_id,
    "plan-correct-append-with-plan-id": plan_correct_append_with_plan_id,
}

if __name__ == "__main__":
    if len(sys.argv) < 2 or sys.argv[1] not in _COMMANDS:
        print(
            f"Usage: {sys.argv[0]} <{'|'.join(_COMMANDS)}>",
            file=sys.stderr,
        )
        sys.exit(1)
    cmd = _COMMANDS[sys.argv[1]]
    cmd()
