"""Unit tests for chat cleanup helpers.

These tests intentionally mock shell boundaries and are kept out of
``test_integration*`` so seam-proof integration evidence remains real-boundary.
"""

from __future__ import annotations

from io import StringIO
from pathlib import Path
from unittest.mock import MagicMock, patch

from returns.result import Failure
from rich.console import Console

from anima.core.schemas import InternalError
from anima.core.schemas.enums import AgentState
from anima.shell.cli_commands.chat_cmd import _cleanup_chat_agent, _is_enoent_error
from anima.shell.state import AgentStateData


def test_cleanup_suppresses_enoent_warnings(tmp_state_dir: Path) -> None:
    """ENOENT-like cleanup failures are classified as suppressible."""
    _ = tmp_state_dir
    enoent_error = InternalError("[Errno 2] No such file or directory: '/path/to/file'")
    assert _is_enoent_error(enoent_error) is True

    enoent_error2 = InternalError("No such file or directory: '/path/to/file'")
    assert _is_enoent_error(enoent_error2) is True

    other_error = InternalError("Permission denied: '/path/to/file'")
    assert _is_enoent_error(other_error) is False


def test_cleanup_warns_on_non_enoent_errors(tmp_state_dir: Path) -> None:
    """Non-ENOENT cleanup failures remain warning eligible."""
    _ = tmp_state_dir
    perm_error = InternalError("Permission denied: '/path/to/file'")
    assert _is_enoent_error(perm_error) is False

    io_error = InternalError("I/O error: Read-only file system")
    assert _is_enoent_error(io_error) is False


def test_cleanup_enoent_produces_no_console_warning(tmp_state_dir: Path) -> None:
    """ENOENT failures are suppressed by cleanup warning gate."""
    _ = tmp_state_dir
    output = StringIO()
    console = Console(file=output, force_terminal=True)

    mock_state = AgentStateData(
        instance_id="test-instance-123",
        persona_name="test-persona",
        trace_id="trace-123",
        state=AgentState.running,
        pid=12345,
    )
    enoent_error = InternalError("[Errno 2] No such file or directory")

    with (
        patch("anima.shell.cli_commands.chat_cmd.read_state") as mock_read,
        patch("anima.shell.cli_commands.chat_cmd.kill_agent_tree") as mock_kill,
        patch("anima.shell.cli_commands.chat_cmd.delete_agent_state") as mock_delete,
    ):
        mock_read.return_value = MagicMock(
            is_success=lambda: True, unwrap=lambda: mock_state
        )
        mock_kill.return_value = Failure(enoent_error)
        mock_delete.return_value = MagicMock(is_success=lambda: True)
        _cleanup_chat_agent(instance_id="test-instance-123", console=console)

    console_output = output.getvalue()
    assert "Warning" not in console_output


def test_cleanup_non_enoent_produces_console_warning(tmp_state_dir: Path) -> None:
    """Non-ENOENT failures still emit operator-visible warning."""
    _ = tmp_state_dir
    output = StringIO()
    console = Console(file=output, force_terminal=True)

    mock_state = AgentStateData(
        instance_id="test-instance-456",
        persona_name="test-persona",
        trace_id="trace-456",
        state=AgentState.running,
        pid=12345,
    )
    perm_error = InternalError("Permission denied: cannot access state directory")

    with (
        patch("anima.shell.cli_commands.chat_cmd.read_state") as mock_read,
        patch("anima.shell.cli_commands.chat_cmd.kill_agent_tree") as mock_kill,
        patch("anima.shell.cli_commands.chat_cmd.delete_agent_state") as mock_delete,
    ):
        mock_read.return_value = MagicMock(
            is_success=lambda: True, unwrap=lambda: mock_state
        )
        mock_kill.return_value = Failure(perm_error)
        mock_delete.return_value = MagicMock(is_success=lambda: True)
        _cleanup_chat_agent(instance_id="test-instance-456", console=console)

    console_output = output.getvalue()
    assert "Warning" in console_output
    assert "Permission denied" in console_output
