"""Pure helper functions shared by talk command modules.

Spec source: talk-deps-refactor.create-talk-deps-container.
"""

from __future__ import annotations

import asyncio
import json

from deal import post, pre


# @invar:allow shell_result: Pure parser helper retained in shell for command behavior preservation
# @shell_orchestration: Pure parsing helper scoped to talk CLI command module
@pre(lambda response_text: response_text is not None)
@post(lambda result: "response" in result and "turn_number" in result)
def parse_talk_response(response_text: str) -> dict[str, str | None]:
    """Parse MCP talk tool response JSON into string fields.

    >>> parse_talk_response('{"response": "hello", "turn_number": 7}')
    {'response': 'hello', 'turn_number': '7'}
    >>> parse_talk_response('{}')
    {'response': '', 'turn_number': '0'}
    """
    data = json.loads(response_text)

    response = data.get("response", "")
    turn_number = data.get("turn_number", 0)

    return {
        "response": None if response is None else str(response),
        "turn_number": None if turn_number is None else str(turn_number),
    }


# @invar:allow shell_result: event-loop exception hook returns None by asyncio contract
# @shell_orchestration: Event-loop exception filtering is shell runtime coordination behavior
def suppress_invalid_state_error(
    loop: asyncio.AbstractEventLoop,
    context: dict[str, object],
) -> None:
    """Suppress teardown InvalidStateError noise, forward all other exceptions.

    Spec source: run-full-test-suite-for-regression-fix requires restoring
    production InvalidStateError suppression behavior for talk attach runtime.
    """
    exception = context.get("exception")
    message_obj = context.get("message", "")
    message = message_obj if isinstance(message_obj, str) else str(message_obj)

    if isinstance(exception, asyncio.InvalidStateError):
        return

    if isinstance(exception, KeyboardInterrupt):
        return  # Suppress Ctrl+C noise during asyncio cleanup

    if "InvalidStateError" in message or "invalid state" in message.lower():
        return

    if "KeyboardInterrupt" in message:
        return

    loop.default_exception_handler(context)
