from __future__ import annotations

import anyio
from functools import partial

from yee88.backends import EngineBackend
from yee88.config import dump_toml
from yee88.telegram import onboarding
from yee88.telegram.api_models import User


def test_mask_token_short() -> None:
    assert onboarding.mask_token("short") == "*****"


def test_mask_token_long() -> None:
    token = "123456789:ABCdefGH"
    masked = onboarding.mask_token(token)
    assert masked.startswith("123456789")
    assert masked.endswith("defGH")
    assert "..." in masked


def test_render_config_escapes() -> None:
    config = dump_toml(
        {
            "default_engine": "codex",
            "transport": "telegram",
            "transports": {
                "telegram": {
                    "bot_token": 'token"with\\quote',
                    "chat_id": 123,
                }
            },
        }
    )
    assert 'default_engine = "codex"' in config
    assert 'transport = "telegram"' in config
    assert "[transports.telegram]" in config
    assert 'bot_token = "token\\"with\\\\quote"' in config
    assert "chat_id = 123" in config
    assert config.endswith("\n")


class FakeQuestion:
    def __init__(self, value):
        self._value = value

    def ask(self):
        return self._value

    async def ask_async(self):
        return self._value


def queue_answers(values):
    it = iter(values)

    def _make(*_args, **_kwargs):
        return FakeQuestion(next(it))

    return _make


def queue_values(values):
    it = iter(values)

    async def _next(*_args, **_kwargs):
        return next(it)

    return _next


def patch_live_services(
    monkeypatch,
    *,
    bot: User,
    chat: onboarding.ChatInfo,
    topics_issue=None,
) -> None:
    async def _get_bot_info(self, _token: str):
        return bot

    async def _wait_for_chat(self, _token: str):
        return chat

    async def _validate_topics(self, _token: str, _chat_id: int, _scope):
        return topics_issue

    monkeypatch.setattr(onboarding.LiveServices, "get_bot_info", _get_bot_info)
    monkeypatch.setattr(onboarding.LiveServices, "wait_for_chat", _wait_for_chat)
    monkeypatch.setattr(onboarding.LiveServices, "validate_topics", _validate_topics)


def test_interactive_setup_skips_when_config_exists(monkeypatch, tmp_path) -> None:
    config_path = tmp_path / "yee88.toml"
    config_path.write_text(
        'transport = "telegram"\n\n[transports.telegram]\n'
        'bot_token = "token"\nchat_id = 123\n',
        encoding="utf-8",
    )
    monkeypatch.setattr(onboarding, "HOME_CONFIG_PATH", config_path)
    assert anyio.run(partial(onboarding.interactive_setup, force=False)) is True


def test_interactive_setup_writes_config(monkeypatch, tmp_path) -> None:
    config_path = tmp_path / "yee88.toml"
    monkeypatch.setattr(onboarding, "HOME_CONFIG_PATH", config_path)

    backend = EngineBackend(id="codex", build_runner=lambda _cfg, _path: None)
    monkeypatch.setattr(onboarding, "list_backends", lambda: [backend])
    monkeypatch.setattr(onboarding.shutil, "which", lambda _cmd: "/usr/bin/codex")

    monkeypatch.setattr(onboarding, "confirm_prompt", queue_values([True, True, True]))
    monkeypatch.setattr(
        onboarding.questionary, "password", queue_answers(["123456789:ABCdef"])
    )
    monkeypatch.setattr(
        onboarding.questionary,
        "select",
        queue_answers(["assistant", "codex"]),
    )
    patch_live_services(
        monkeypatch,
        bot=User(id=1, username="my_bot"),
        chat=onboarding.ChatInfo(
            chat_id=123,
            username="alice",
            title=None,
            first_name="Alice",
            last_name=None,
            chat_type="private",
        ),
    )

    assert anyio.run(partial(onboarding.interactive_setup, force=False)) is True
    saved = config_path.read_text(encoding="utf-8")
    assert 'transport = "telegram"' in saved
    assert "[transports.telegram]" in saved
    assert 'bot_token = "123456789:ABCdef"' in saved
    assert "chat_id = 123" in saved
    assert 'session_mode = "chat"' in saved
    assert "show_resume_line = false" in saved
    assert "[transports.telegram.topics]" in saved
    assert "enabled = false" in saved
    assert 'default_engine = "codex"' in saved


def test_interactive_setup_preserves_projects(monkeypatch, tmp_path) -> None:
    config_path = tmp_path / "yee88.toml"
    config_path.write_text(
        'default_project = "z80"\n\n[projects.z80]\npath = "/tmp/repo"\n',
        encoding="utf-8",
    )
    monkeypatch.setattr(onboarding, "HOME_CONFIG_PATH", config_path)

    backend = EngineBackend(id="codex", build_runner=lambda _cfg, _path: None)
    monkeypatch.setattr(onboarding, "list_backends", lambda: [backend])
    monkeypatch.setattr(onboarding.shutil, "which", lambda _cmd: "/usr/bin/codex")

    monkeypatch.setattr(onboarding, "confirm_prompt", queue_values([True, True, True, True]))
    monkeypatch.setattr(
        onboarding.questionary, "password", queue_answers(["123456789:ABCdef"])
    )
    monkeypatch.setattr(
        onboarding.questionary,
        "select",
        queue_answers(["assistant", "codex"]),
    )
    patch_live_services(
        monkeypatch,
        bot=User(id=1, username="my_bot"),
        chat=onboarding.ChatInfo(
            chat_id=123,
            username="alice",
            title=None,
            first_name="Alice",
            last_name=None,
            chat_type="private",
        ),
    )

    assert anyio.run(partial(onboarding.interactive_setup, force=True)) is True
    saved = config_path.read_text(encoding="utf-8")
    assert "[projects.z80]" in saved
    assert 'path = "/tmp/repo"' in saved


def test_interactive_setup_no_agents_aborts(monkeypatch, tmp_path) -> None:
    config_path = tmp_path / "yee88.toml"
    monkeypatch.setattr(onboarding, "HOME_CONFIG_PATH", config_path)

    backend = EngineBackend(id="codex", build_runner=lambda _cfg, _path: None)
    monkeypatch.setattr(onboarding, "list_backends", lambda: [backend])
    monkeypatch.setattr(onboarding.shutil, "which", lambda _cmd: None)

    monkeypatch.setattr(onboarding, "confirm_prompt", queue_values([True, False]))
    monkeypatch.setattr(
        onboarding.questionary, "password", queue_answers(["123456789:ABCdef"])
    )
    monkeypatch.setattr(
        onboarding.questionary,
        "select",
        queue_answers(["assistant"]),
    )
    patch_live_services(
        monkeypatch,
        bot=User(id=1, username="my_bot"),
        chat=onboarding.ChatInfo(
            chat_id=123,
            username="alice",
            title=None,
            first_name="Alice",
            last_name=None,
            chat_type="private",
        ),
    )

    assert anyio.run(partial(onboarding.interactive_setup, force=False)) is False
    assert not config_path.exists()


def test_interactive_setup_recovers_from_malformed_toml(monkeypatch, tmp_path) -> None:
    config_path = tmp_path / "yee88.toml"
    bad_toml = 'transport = "telegram"\n[transports\n'
    config_path.write_text(bad_toml, encoding="utf-8")
    monkeypatch.setattr(onboarding, "HOME_CONFIG_PATH", config_path)

    backend = EngineBackend(id="codex", build_runner=lambda _cfg, _path: None)
    monkeypatch.setattr(onboarding, "list_backends", lambda: [backend])
    monkeypatch.setattr(onboarding.shutil, "which", lambda _cmd: "/usr/bin/codex")

    monkeypatch.setattr(onboarding, "confirm_prompt", queue_values([True, True, True, True]))
    monkeypatch.setattr(
        onboarding.questionary, "password", queue_answers(["123456789:ABCdef"])
    )
    monkeypatch.setattr(
        onboarding.questionary,
        "select",
        queue_answers(["assistant", "codex"]),
    )
    patch_live_services(
        monkeypatch,
        bot=User(id=1, username="my_bot"),
        chat=onboarding.ChatInfo(
            chat_id=123,
            username="alice",
            title=None,
            first_name="Alice",
            last_name=None,
            chat_type="private",
        ),
    )

    assert anyio.run(partial(onboarding.interactive_setup, force=True)) is True
    backup = config_path.with_suffix(".toml.bak")
    assert backup.exists()
    assert backup.read_text(encoding="utf-8") == bad_toml
    saved = config_path.read_text(encoding="utf-8")
    assert "[transports.telegram]" in saved
    assert 'bot_token = "123456789:ABCdef"' in saved


def test_capture_chat_id_with_token(monkeypatch) -> None:
    patch_live_services(
        monkeypatch,
        bot=User(id=1, username="my_bot"),
        chat=onboarding.ChatInfo(
            chat_id=456,
            username=None,
            title="yee88",
            first_name=None,
            last_name=None,
            chat_type="supergroup",
        ),
    )

    chat = anyio.run(partial(onboarding.capture_chat_id, token="123456789:ABCdef"))

    assert chat is not None
    assert chat.chat_id == 456


def test_capture_chat_id_prompts_for_token(monkeypatch) -> None:
    async def _prompt_token(_ui, _svc):
        return ("token", User(id=1, username="bot"))

    monkeypatch.setattr(onboarding, "prompt_token", _prompt_token)
    patch_live_services(
        monkeypatch,
        bot=User(id=1, username="bot"),
        chat=onboarding.ChatInfo(
            chat_id=789,
            username="alice",
            title=None,
            first_name="Alice",
            last_name=None,
            chat_type="private",
        ),
    )

    chat = anyio.run(onboarding.capture_chat_id)

    assert chat is not None
    assert chat.chat_id == 789
