import asyncio
from collections.abc import Awaitable, Callable

SendJson = Callable[[dict[str, object]], Awaitable[None]]

# Maps sender JID → (future, {1-based-number-str: label})
_pending_asks: dict[str, tuple[asyncio.Future[str], dict[str, str]]] = {}


def make_ask_user_callback(
    send_json: SendJson,
    to_jid: str,
) -> Callable[[str, list[dict[str, str]]], Awaitable[str]]:
    async def ask_user(question: str, options: list[dict[str, str]]) -> str:
        if not options:
            return ""

        loop = asyncio.get_running_loop()
        future: asyncio.Future[str] = loop.create_future()

        number_map: dict[str, str] = {}
        lines: list[str] = [question, ""]

        for index, option in enumerate(options):
            label = str(option.get("label", "")).strip()
            if not label:
                continue
            number = str(index + 1)
            number_map[number] = label
            lines.append(f"{number}. {label}")

        if not number_map:
            return options[0].get("label", "")

        _pending_asks[to_jid] = (future, number_map)
        await send_json(
            {
                "action": "send_text",
                "to": to_jid,
                "text": "\n".join(lines),
            }
        )

        return await future

    return ask_user


def resolve_pending_text_response(sender: str, text: str, _is_button_reply: bool = False) -> bool:
    entry = _pending_asks.pop(sender, None)
    if entry is None:
        return False

    future, number_map = entry
    if future.done():
        return True

    normalized = text.strip()
    if normalized in number_map:
        future.set_result(number_map[normalized])
    else:
        future.set_result(normalized)
    return True
