"""Tests for user synchronization Discord cog commands.

These tests include a lightweight discord stub so they can run in CI environments
without py-cord installed.
"""

from importlib.util import find_spec
from types import ModuleType, SimpleNamespace
from unittest import IsolatedAsyncioTestCase
from unittest.mock import AsyncMock, Mock, patch
import sys

if find_spec("discord") is None:
    discord_stub = ModuleType("discord")

    class _DiscordError(Exception):
        pass

    class _ChannelType:
        private_thread = "private_thread"

    discord_stub.Member = type("Member", (), {})
    discord_stub.User = type("User", (), {})
    discord_stub.Message = type("Message", (), {})
    discord_stub.Interaction = type("Interaction", (), {})
    discord_stub.ChannelType = _ChannelType
    discord_stub.NotFound = _DiscordError
    discord_stub.Forbidden = _DiscordError
    discord_stub.HTTPException = _DiscordError

    embeds_stub = ModuleType("discord.embeds")
    embeds_stub.Embed = type("Embed", (), {})

    commands_stub = ModuleType("discord.ext.commands")
    commands_stub.Cog = type("Cog", (), {})

    def _passthrough_decorator(*_args, **_kwargs):
        def _wrapper(func):
            return func

        return _wrapper

    commands_stub.slash_command = _passthrough_decorator
    commands_stub.message_command = _passthrough_decorator
    commands_stub.user_command = _passthrough_decorator

    ext_stub = ModuleType("discord.ext")
    ext_stub.commands = commands_stub

    sys.modules.setdefault("discord", discord_stub)
    sys.modules.setdefault("discord.embeds", embeds_stub)
    sys.modules.setdefault("discord.ext", ext_stub)
    sys.modules.setdefault("discord.ext.commands", commands_stub)

from jaystools.cogs.me_recruter import UserSyncCommands  # pylint: disable=wrong-import-position


class TestUserSyncCommands(IsolatedAsyncioTestCase):
    """Behavior tests for sync command helper methods."""

    async def test_queue_sync_for_discord_user_id_queues_task(self):
        """Queue task with actor and target users when link and main are present."""

        cog = UserSyncCommands(bot=Mock())

        response = SimpleNamespace(send_message=AsyncMock())
        ctx = SimpleNamespace(response=response, user=SimpleNamespace(id=55))
        discord_user_id = 77

        auth_user = SimpleNamespace(
            pk=10,
            profile=SimpleNamespace(main_character=SimpleNamespace(character_name="Pilot One")),
        )
        actor_user = SimpleNamespace(pk=20)

        with patch(
            "jaystools.cogs.me_recruter._get_auth_user_from_discord_user_id",
            side_effect=[auth_user, actor_user],
        ):
            with patch("jaystools.cogs.me_recruter.sync_user_esi_and_discord.delay") as mock_delay:
                await cog._queue_sync_for_discord_user_id(  # pylint: disable=protected-access
                    ctx,
                    discord_user_id,
                )

        mock_delay.assert_called_once_with(user_pk=10, triggered_by_user_pk=20)
        response.send_message.assert_awaited_once()
        _, kwargs = response.send_message.await_args
        self.assertTrue(kwargs["ephemeral"])

    async def test_queue_sync_for_discord_user_id_handles_missing_link(self):
        """Do not queue task and reply ephemerally when no Auth link exists."""

        cog = UserSyncCommands(bot=Mock())

        response = SimpleNamespace(send_message=AsyncMock())
        ctx = SimpleNamespace(response=response, user=SimpleNamespace(id=55))
        discord_user_id = 77

        with patch("jaystools.cogs.me_recruter._get_auth_user_from_discord_user_id", return_value=None):
            with patch("jaystools.cogs.me_recruter.sync_user_esi_and_discord.delay") as mock_delay:
                await cog._queue_sync_for_discord_user_id(  # pylint: disable=protected-access
                    ctx,
                    discord_user_id,
                )

        mock_delay.assert_not_called()
        response.send_message.assert_awaited_once()

    async def test_user_context_passes_discord_user_id(self):
        """User context command forwards selected user ID to shared queue helper."""

        cog = UserSyncCommands(bot=Mock())
        ctx = SimpleNamespace()
        user = SimpleNamespace(id=88)

        with patch.object(cog, "_queue_sync_for_discord_user_id", new_callable=AsyncMock) as mock_queue:
            cmd = cog.sync_user_esi_user_context
            if hasattr(cmd, "callback"):
                await cmd.callback(cog, ctx, user)
            else:
                await cmd(ctx, user)

        mock_queue.assert_awaited_once_with(ctx, 88)

    async def test_message_context_passes_author_id(self):
        """Message context command forwards message author ID to shared queue helper."""

        cog = UserSyncCommands(bot=Mock())
        ctx = SimpleNamespace()
        message = SimpleNamespace(author=SimpleNamespace(id=99))

        with patch.object(cog, "_queue_sync_for_discord_user_id", new_callable=AsyncMock) as mock_queue:
            cmd = cog.sync_user_esi_message_context
            if hasattr(cmd, "callback"):
                await cmd.callback(cog, ctx, message)
            else:
                await cmd(ctx, message)

        mock_queue.assert_awaited_once_with(ctx, 99)
