"""Interactive chat tests using fake models on the real server.

Tests that `navari chat` correctly displays agent messages, tool cards,
and prompts for user input via stdin/stdout, using special commands
that activate fake models on the server.

Requires:
1. A running Navari server with test models enabled (DEV)
2. Valid credentials (run `navari login <url>` first)

Run with: uv run pytest cli/tests/test_chat_interactive.py -v -s
"""

import json
import os
import subprocess

import pytest
from navari_cli.cli import app
from typer.testing import CliRunner

runner = CliRunner()

# Environment for subprocess: force UTF-8 output and disable Rich formatting
# to avoid Windows cp1252 encoding errors with Unicode characters (e.g. checkmarks)
_SUBPROCESS_ENV = {**os.environ, "PYTHONIOENCODING": "utf-8", "NO_COLOR": "1"}


@pytest.fixture
def _require_server(server_url):
    """Skip if no server configured."""


@pytest.mark.usefixtures("_require_server")
class TestChatAskTools:
    """Test interactive chat with :test_ask_tools fake model via real CLI process.

    The :test_ask_tools fake model sends the following tool calls:
    1. send_message_to_user: "Hello user, let's mock some questions!"
    2. ask_user: "What do you want to know?"  -> waits for input
    3. send_message_to_user: "ok next question:"
    4. ask_user_with_examples: "select an option" -> waits for input
    5. ask_user_for_confirmation: "Would you like to continue?" -> waits for input
    6. final_result: "thank you"

    Tests run the CLI as a subprocess with stdin piped, simulating
    a user typing messages in the REPL.
    """

    def test_ask_tools_full_interactive(self):
        # Stdin: first message is the query, then 3 responses to ask_user prompts,
        # then /quit to exit the REPL
        stdin_lines = [
            ":test_ask_tools",  # User's first message in the REPL
            "I want to know about weather",  # Response to ask_user
            "first option",  # Response to ask_user_with_examples
            "yes",  # Response to ask_user_for_confirmation
            "/quit",  # Exit the REPL
        ]
        stdin_input = "\n".join(stdin_lines) + "\n"

        result = subprocess.run(
            ["navari", "chat", "-n", "-t", "CLI Ask Tools Interactive"],
            input=stdin_input,
            capture_output=True,
            encoding="utf-8",
            timeout=120,
            env=_SUBPROCESS_ENV,
        )

        output = result.stdout + result.stderr

        # Verify conversation was created
        assert "Created conversation" in output, f"Missing conversation creation in:\n{output}"

        # Verify send_message_to_user content is displayed (no tool card for this one)
        assert "Hello user" in output, f"Missing greeting in:\n{output}"

        # Verify tool cards are shown for ask_user tools (consistent with frontend)
        assert 'use tool "ask_user"' in output, f"Missing ask_user tool card in:\n{output}"
        assert 'use tool "ask_user_with_examples"' in output, f"Missing ask_user_with_examples tool card in:\n{output}"
        assert 'use tool "ask_user_for_confirmation"' in output, (
            f"Missing ask_user_for_confirmation tool card in:\n{output}"
        )

        # Verify ask_user question is displayed
        assert "What do you want to know" in output, f"Missing ask_user question in:\n{output}"

        # Verify ask_user_with_examples shows examples
        assert "first available option" in output, f"Missing example 1 in:\n{output}"
        assert "second option" in output, f"Missing example 2 in:\n{output}"

        # Verify ask_user_for_confirmation question
        assert "Would you like to continue" in output, f"Missing confirmation question in:\n{output}"

        # Verify final_result tool card and summary
        assert 'use tool "final_result"' in output, f"Missing final_result tool card in:\n{output}"
        assert "thank you" in output.lower(), f"Missing final result in:\n{output}"


@pytest.mark.usefixtures("_require_server")
class TestChatTodoList:
    """Test interactive chat with :test_todo_list fake model.

    The :test_todo_list model calls send_message_to_user and write_to_do_file
    multiple times, then final_result. Verifies that the CLI displays all
    tool cards and agent messages correctly.
    """

    # Expected strings that should appear in both chat output and stored messages
    EXPECTED = [
        "Starting authentication system implementation",
        "Created task list",
        "write_to_do_file",
        "Build a User Authentication System",
        "Design authentication architecture",
        "Authentication system implementation completed",
    ]

    def test_todo_list_tool_display(self):
        # Create conversation via CliRunner to get the ID
        result = runner.invoke(app, ["--format", "json", "conversations", "create", "--title", "CLI Todo List Test"])
        assert result.exit_code == 0
        conv = json.loads(result.output)
        conv_id = conv["id"]

        try:
            # Run chat via subprocess against the created conversation
            stdin_input = ":test_todo_list\n/quit\n"

            chat_result = subprocess.run(
                ["navari", "chat"],
                input=stdin_input,
                capture_output=True,
                encoding="utf-8",
                timeout=120,
                env=_SUBPROCESS_ENV,
            )

            chat_output = chat_result.stdout + chat_result.stderr

            # Verify conversation was resumed (not recreated)
            assert "Resuming:" in chat_output

            # Verify expected content in live chat output
            for expected in self.EXPECTED:
                assert expected in chat_output, f"Missing '{expected}' in chat output:\n{chat_output}"

            # Chat-only assertions (not in stored messages)
            assert "done" in chat_output, f"Missing done count in chat output:\n{chat_output}"

            # Verify the same data renders in `conversations messages` (plain format)
            msg_result = runner.invoke(app, ["conversations", "messages", conv_id])
            assert msg_result.exit_code == 0, f"messages command failed:\n{msg_result.output}"
            msg_output = msg_result.output

            for expected in self.EXPECTED:
                assert expected in msg_output, f"Missing '{expected}' in messages:\n{msg_output}"

            # Plain format should also render the todo done count
            assert "done" in msg_output, f"Missing done count in messages:\n{msg_output}"
        finally:
            runner.invoke(app, ["conversations", "delete", conv_id, "--yes"])
