"""Helper script for repl_smoke.robot smoke tests.

Each function is a self-contained check used as a Robot Framework keyword.
"""

from __future__ import annotations

import os
import sys
from io import StringIO
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)

from cleveragents.cli.commands.repl import (  # noqa: E402
    _get_prompt_context,
    _setup_completer,
    dispatch_command,
    run_repl,
)

# ---------------------------------------------------------------------------
# Fake input helper
# ---------------------------------------------------------------------------


class _FakeInput:
    """Feed predetermined lines then raise ``EOFError``."""

    def __init__(self, lines: list[str]) -> None:
        self._lines = list(lines)
        self._idx = 0

    def __call__(self, prompt: str = "") -> str:
        if self._idx >= len(self._lines):
            raise EOFError
        line = self._lines[self._idx]
        self._idx += 1
        return line


def _run(lines: list[str]) -> tuple[int, str]:
    from rich.console import Console

    buf = StringIO()
    console = Console(file=buf, no_color=True, width=200)
    fake = _FakeInput(lines)
    with (
        patch("cleveragents.cli.commands.repl._console", console),
        patch("builtins.input", fake),
    ):
        code = run_repl(no_history=True)
    return code, buf.getvalue()


# ---------------------------------------------------------------------------
# Robot keywords
# ---------------------------------------------------------------------------


def get_default_prompt() -> str:
    """Return prompt context with no environment variables set."""
    old_proj = os.environ.pop("CLEVERAGENTS_PROJECT", None)
    old_plan = os.environ.pop("CLEVERAGENTS_PLAN", None)
    try:
        return _get_prompt_context()
    finally:
        if old_proj is not None:
            os.environ["CLEVERAGENTS_PROJECT"] = old_proj
        if old_plan is not None:
            os.environ["CLEVERAGENTS_PLAN"] = old_plan


def get_prompt_with_project(project: str) -> str:
    """Return prompt context with CLEVERAGENTS_PROJECT set."""
    old = os.environ.get("CLEVERAGENTS_PROJECT")
    os.environ["CLEVERAGENTS_PROJECT"] = project
    try:
        return _get_prompt_context()
    finally:
        if old is None:
            os.environ.pop("CLEVERAGENTS_PROJECT", None)
        else:
            os.environ["CLEVERAGENTS_PROJECT"] = old


def get_prompt_with_project_and_plan(project: str, plan: str) -> str:
    """Return prompt context with both env vars set."""
    old_proj = os.environ.get("CLEVERAGENTS_PROJECT")
    old_plan = os.environ.get("CLEVERAGENTS_PLAN")
    os.environ["CLEVERAGENTS_PROJECT"] = project
    os.environ["CLEVERAGENTS_PLAN"] = plan
    try:
        return _get_prompt_context()
    finally:
        if old_proj is None:
            os.environ.pop("CLEVERAGENTS_PROJECT", None)
        else:
            os.environ["CLEVERAGENTS_PROJECT"] = old_proj
        if old_plan is None:
            os.environ.pop("CLEVERAGENTS_PLAN", None)
        else:
            os.environ["CLEVERAGENTS_PLAN"] = old_plan


def dispatch_argv(*args: str) -> int:
    """Call ``dispatch_command`` with the given argv tokens."""
    return dispatch_command(list(args))


def run_repl_with_eof() -> int:
    """Run the REPL with no input (immediate EOF)."""
    code, _ = _run([])
    return code


def run_repl_with_help() -> str:
    """Run the REPL, send ``:help`` then exit, return output."""
    _, output = _run([":help"])
    return output


def run_repl_with_bang_bang() -> str:
    """Run the REPL, send ``!!`` with no prior command, return output."""
    _, output = _run(["!!"])
    return output


def verify_completer() -> bool:
    """Verify that the tab completer is installed and recognises commands."""
    import readline

    _setup_completer()
    # The completer should match ':help' when given ':'
    completer_func = readline.get_completer()
    if completer_func is None:
        return False
    match = completer_func(":", 0)
    return match is not None and match.startswith(":")
