text: # -*- coding: utf-8 -*-
  # cython: language_level=3
  # BSD 3-Clause License
  #
  # Copyright (c) 2020-2022, Faster Speeding
  # All rights reserved.
  #
  # Redistribution and use in source and binary forms, with or without
  # modification, are permitted provided that the following conditions are met:
  #
  # * Redistributions of source code must retain the above copyright notice, this
  #   list of conditions and the following disclaimer.
  #
  # * Redistributions in binary form must reproduce the above copyright notice,
  #   this list of conditions and the following disclaimer in the documentation
  #   and/or other materials provided with the distribution.
  #
  # * Neither the name of the copyright holder nor the names of its
  #   contributors may be used to endorse or promote products derived from
  #   this software without specific prior written permission.
  #
  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  
  # pyright: reportUnknownMemberType=none
  # pyright: reportPrivateUsage=none
  # This leads to too many false-positives around mocks.
  
  from unittest import mock
  
  import hikari
  import pytest
  from hikari import traits
  
  import tanjun
  
  
  class TestAutocompleteOption:
      def test_is_focused_property(self):
          mock_raw_option = mock.Mock()
          option = tanjun.context.AutocompleteOption(mock.Mock(), mock_raw_option)
  
          assert option.is_focused is mock_raw_option.is_focused
  
  
  class TestAutocompleteContext:
      @pytest.fixture()
      def mock_client(self) -> tanjun.Client:
          return mock.AsyncMock(tanjun.Client)
  
      @pytest.fixture()
      def mock_interaction(self) -> hikari.AutocompleteInteraction:
          return mock.Mock(options=[mock.Mock(is_focused=True)])
  
      @pytest.fixture()
      def context(
          self, mock_client: tanjun.Client, mock_interaction: hikari.AutocompleteInteraction
      ) -> tanjun.context.AutocompleteContext:
          return tanjun.context.AutocompleteContext(mock_client, mock_interaction)
  
      def test_author_property(
          self, context: tanjun.context.AutocompleteContext, mock_interaction: hikari.AutocompleteInteraction
      ):
          assert context.author is mock_interaction.user
  
      def test_channel_id_property(
          self, context: tanjun.context.AutocompleteContext, mock_interaction: hikari.AutocompleteInteraction
      ):
          assert context.channel_id is mock_interaction.channel_id
  
      def test_cache_property(self, context: tanjun.context.AutocompleteContext, mock_client: tanjun.Client):
          assert context.cache is mock_client.cache
  
      def test_client_property(self, context: tanjun.context.AutocompleteContext, mock_client: tanjun.Client):
          assert context.client is mock_client
  
      def test_created_at_property(
          self, context: tanjun.context.AutocompleteContext, mock_interaction: hikari.AutocompleteInteraction
      ):
          assert context.created_at is mock_interaction.created_at
  
      def test_events_property(self, context: tanjun.context.AutocompleteContext, mock_client: tanjun.Client):
          assert context.events is mock_client.events
  
      def test_focused_property(self):
          focused_option = mock.Mock(is_focused=True)
          mock_interaction = mock.Mock(options=[mock.Mock(is_focused=False), focused_option, mock.Mock(is_focused=False)])
          context = tanjun.context.AutocompleteContext(mock.Mock(tanjun.Client), mock_interaction)
  
          assert isinstance(context.focused, tanjun.context.AutocompleteOption)
          assert context.focused._resolved is mock_interaction.resolved
          assert context.focused._option is focused_option
  
      def test_guild_id_property(
          self, context: tanjun.context.AutocompleteContext, mock_interaction: hikari.AutocompleteInteraction
      ):
          assert context.guild_id is mock_interaction.guild_id
  
      def test_member_property(
          self, context: tanjun.context.AutocompleteContext, mock_interaction: hikari.AutocompleteInteraction
      ):
          assert context.member is mock_interaction.member
  
      def test_server_property(self, context: tanjun.context.AutocompleteContext, mock_client: tanjun.Client):
          assert context.server is mock_client.server
  
      def test_rest_property(self, context: tanjun.context.AutocompleteContext, mock_client: tanjun.Client):
          assert context.rest is mock_client.rest
  
      def test_shard_property(
          self,
          context: tanjun.context.AutocompleteContext,
          mock_client: mock.Mock,
          mock_interaction: hikari.AutocompleteInteraction,
      ):
          mock_shard = mock.Mock()
          mock_client.shards = mock.MagicMock(spec=traits.ShardAware, shard_count=5, shards={2: mock_shard})
          mock_interaction.guild_id = hikari.Snowflake(123321123312)
  
          assert context.shard is mock_shard
  
      def test_shard_property_when_dm(
          self,
          context: tanjun.context.AutocompleteContext,
          mock_client: mock.Mock,
          mock_interaction: hikari.AutocompleteInteraction,
      ):
          mock_shard = mock.Mock()
          mock_client.shards = mock.Mock(shards={0: mock_shard})
          mock_interaction.guild_id = None
  
          assert context.shard is mock_shard
  
      def test_shard_property_when_no_shards(self, context: tanjun.context.AutocompleteContext):
          context._client = mock.Mock(shards=None)
  
          assert context.shard is None
  
      def test_shards_property(self, context: tanjun.context.AutocompleteContext, mock_client: tanjun.Client):
          assert context.shards is mock_client.shards
  
      def test_voice_property(self, context: tanjun.context.AutocompleteContext, mock_client: tanjun.Client):
          assert context.voice is mock_client.voice
  
      def test_has_responded_property(self, context: tanjun.context.AutocompleteContext):
          assert context.has_responded is False
  
      def test_interaction_property(
          self, context: tanjun.context.AutocompleteContext, mock_interaction: hikari.AutocompleteInteraction
      ):
          assert context.interaction is mock_interaction
  
      def test_options_property(self):
          mock_option_1 = mock.Mock()
          mock_option_2 = mock.Mock()
          mock_option_3 = mock.Mock()
          context = tanjun.context.AutocompleteContext(
              mock.Mock(tanjun.Client), mock.Mock(options=[mock_option_1, mock_option_2, mock_option_3])
          )
  
          assert len(context.options) == 3
          for (name, option), raw_option in zip(context.options.items(), [mock_option_1, mock_option_2, mock_option_3]):
              assert isinstance(option, tanjun.context.AutocompleteOption)
              assert name is option.name
              assert option._option is raw_option
  
      # def test_options_property_for_top_level_command(self, mock_client: mock.Mock):
      #     mock_option_1 = mock.Mock()
      #     mock_option_1.name = "hi"
      #     mock_option_2 = mock.Mock()
      #     mock_option_2.name = "bye"
      #     context = tanjun.context.SlashContext(
      #         mock_client,
      #         mock.Mock(),
      #         mock.Mock(type=hikari.OptionType.SUB_COMMAND, options=[mock_option_1, mock_option_2]),
      #         command=mock.Mock(),
      #         component=mock.Mock(),
      #     )
  
      #     assert len(context.options) == 2
      #     assert context.options["hi"].type is mock_option_1.type
      #     assert context.options["hi"].value is mock_option_1.value
      #     assert context.options["hi"].name is mock_option_1.name
      #     assert isinstance(context.options["hi"], tanjun.context.SlashOption)
  
      #     assert context.options["bye"].type is mock_option_2.type
      #     assert context.options["bye"].value is mock_option_2.value
      #     assert context.options["bye"].name is mock_option_2.name
      #     assert isinstance(context.options["bye"], tanjun.context.SlashOption)
  
      # def test_options_property_for_command_group(self, mock_client: mock.Mock):
      #     mock_option_1 = mock.Mock()
      #     mock_option_1.name = "kachow"
      #     mock_option_2 = mock.Mock()
      #     mock_option_2.name = "nyaa"
      #     group_option = mock.Mock(type=hikari.OptionType.SUB_COMMAND, options=[mock_option_1, mock_option_2])
      #     context = tanjun.context.SlashContext(
      #         mock_client,
      #         mock.Mock(),
      #         mock.Mock(type=hikari.OptionType.SUB_COMMAND_GROUP, options=[group_option]),
      #         command=mock.Mock(),
      #         component=mock.Mock(),
      #     )
  
      #     assert len(context.options) == 2
      #     assert context.options["kachow"].type is mock_option_1.type
      #     assert context.options["kachow"].value is mock_option_1.value
      #     assert context.options["kachow"].name is mock_option_1.name
      #     assert isinstance(context.options["kachow"], tanjun.context.SlashOption)
  
      #     assert context.options["nyaa"].type is mock_option_2.type
      #     assert context.options["nyaa"].value is mock_option_2.value
      #     assert context.options["nyaa"].name is mock_option_2.name
      #     assert isinstance(context.options["nyaa"], tanjun.context.SlashOption)
  
      # @pytest.mark.parametrize("raw_options", [None, []])
      # def test_options_property_for_command_group_with_no_sub_option(
      #     self, mock_client: mock.Mock, raw_options: typing.Optional[list[hikari.OptionType]]
      # ):
      #     group_option = mock.Mock(type=hikari.OptionType.SUB_COMMAND, options=raw_options)
      #     context = tanjun.context.SlashContext(
      #         mock_client,
      #         mock.Mock(),
      #         mock.Mock(type=hikari.OptionType.SUB_COMMAND_GROUP, options=[group_option]),
      #         command=mock.Mock(),
      #         component=mock.Mock(),
      #     )
  
      #     assert context.options == {}
  
      # def test_options_property_for_sub_command_group(self, mock_client: mock.Mock):
      #     mock_option_1 = mock.Mock()
      #     mock_option_1.name = "meow"
      #     mock_option_2 = mock.Mock()
      #     mock_option_2.name = "nya"
      #     sub_group_option = mock.Mock(type=hikari.OptionType.SUB_COMMAND, options=[mock_option_1, mock_option_2])
      #     group_option = mock.Mock(type=hikari.OptionType.SUB_COMMAND_GROUP, options=[sub_group_option])
      #     context = tanjun.context.SlashContext(
      #         mock_client,
      #         mock.Mock(),
      #         mock.Mock(type=hikari.OptionType.SUB_COMMAND_GROUP, options=[group_option]),
      #         command=mock.Mock(),
      #         component=mock.Mock(),
      #     )
  
      #     assert len(context.options) == 2
      #     assert context.options["meow"].type is mock_option_1.type
      #     assert context.options["meow"].value is mock_option_1.value
      #     assert context.options["meow"].name is mock_option_1.name
      #     assert isinstance(context.options["meow"], tanjun.context.SlashOption)
  
      #     assert context.options["nya"].type is mock_option_2.type
      #     assert context.options["nya"].value is mock_option_2.value
      #     assert context.options["nya"].name is mock_option_2.name
      #     assert isinstance(context.options["nya"], tanjun.context.SlashOption)
  
      @pytest.mark.asyncio()
      async def test_fetch_channel(self, context: tanjun.context.AutocompleteContext, mock_interaction: mock.Mock):
          mock_interaction.fetch_channel = mock.AsyncMock()
  
          result = await context.fetch_channel()
  
          assert result is mock_interaction.fetch_channel.return_value
          mock_interaction.fetch_channel.assert_awaited_once_with()
  
      @pytest.mark.asyncio()
      async def test_fetch_guild(self, context: tanjun.context.AutocompleteContext, mock_interaction: mock.Mock):
          mock_interaction.fetch_guild = mock.AsyncMock()
  
          result = await context.fetch_guild()
  
          assert result is mock_interaction.fetch_guild.return_value
          mock_interaction.fetch_guild.assert_awaited_once_with()
  
      def test_get_channel(self, context: tanjun.context.AutocompleteContext, mock_interaction: mock.Mock):
          result = context.get_channel()
  
          assert result is mock_interaction.get_channel.return_value
          mock_interaction.get_channel.assert_called_once_with()
  
      def test_get_guild(self, context: tanjun.context.AutocompleteContext, mock_interaction: mock.Mock):
          result = context.get_guild()
  
          assert result is mock_interaction.get_guild.return_value
          mock_interaction.get_guild.assert_called_once_with()
  
      @pytest.mark.asyncio()
      async def test_set_choices(self):
          mock_interaction = mock.AsyncMock(options=[mock.Mock(is_focused=True)])
          context = tanjun.context.AutocompleteContext(mock.Mock(tanjun.Client), mock_interaction)
          assert context.has_responded is False
  
          result = await context.set_choices({"hi": "bye"}, ok="45")
  
          assert result is None
          assert context.has_responded is True
          mock_interaction.create_response.assert_awaited_once_with(
              [hikari.CommandChoice(name="hi", value="bye"), hikari.CommandChoice(name="ok", value="45")]
          )
  
      @pytest.mark.asyncio()
      async def test_set_choices_when_no_options(self):
          mock_interaction = mock.AsyncMock(options=[mock.Mock(is_focused=True)])
          context = tanjun.context.AutocompleteContext(mock.Mock(tanjun.Client), mock_interaction)
  
          result = await context.set_choices()
  
          assert result is None
          mock_interaction.create_response.assert_awaited_once_with([])
  
      @pytest.mark.asyncio()
      async def test_set_choices_when_iterable(self):
          mock_interaction = mock.AsyncMock(options=[mock.Mock(is_focused=True)])
          context = tanjun.context.AutocompleteContext(mock.Mock(tanjun.Client), mock_interaction)
  
          result = await context.set_choices([("echo", "delta"), ("hi", "bye"), ("goof", "meow")])
  
          assert result is None
          mock_interaction.create_response.assert_awaited_once_with(
              [
                  hikari.CommandChoice(name="echo", value="delta"),
                  hikari.CommandChoice(name="hi", value="bye"),
                  hikari.CommandChoice(name="goof", value="meow"),
              ]
          )
  
      @pytest.mark.asyncio()
      async def test_set_choices_when_future_based(self):
          mock_future = mock.Mock()
          mock_interaction = mock.Mock(options=[mock.Mock(is_focused=True)])
          context = tanjun.context.AutocompleteContext(mock.Mock(tanjun.Client), mock_interaction, future=mock_future)
  
          result = await context.set_choices({"meow": "neko", "woof": "borf"}, bark="moo")
  
          assert result is None
          mock_future.set_result.assert_called_once_with(mock_interaction.build_response.return_value)
          mock_interaction.build_response.assert_called_once_with(
              [
                  hikari.CommandChoice(name="meow", value="neko"),
                  hikari.CommandChoice(name="woof", value="borf"),
                  hikari.CommandChoice(name="bark", value="moo"),
              ]
          )
  
      @pytest.mark.asyncio()
      async def test_set_choices_when_future_based_and_iterable(self):
          mock_future = mock.Mock()
          mock_interaction = mock.Mock(options=[mock.Mock(is_focused=True)])
          context = tanjun.context.AutocompleteContext(mock.Mock(tanjun.Client), mock_interaction, future=mock_future)
          assert context.has_responded is False
  
          result = await context.set_choices([("japan", "weeb"), ("england", "idk")], usa="lol")
  
          assert result is None
          mock_future.set_result.assert_called_once_with(mock_interaction.build_response.return_value)
          mock_interaction.build_response.assert_called_once_with(
              [
                  hikari.CommandChoice(name="japan", value="weeb"),
                  hikari.CommandChoice(name="england", value="idk"),
                  hikari.CommandChoice(name="usa", value="lol"),
              ]
          )
          assert context.has_responded is True
  
      @pytest.mark.asyncio()
      async def test_set_choices_when_future_based_and_no_options(self):
          mock_future = mock.Mock()
          mock_interaction = mock.Mock(options=[mock.Mock(is_focused=True)])
          context = tanjun.context.AutocompleteContext(mock.Mock(tanjun.Client), mock_interaction, future=mock_future)
  
          result = await context.set_choices()
  
          assert result is None
          mock_future.set_result.assert_called_once_with(mock_interaction.build_response.return_value)
          mock_interaction.build_response.assert_called_once_with([])
  
      @pytest.mark.asyncio()
      async def test_set_choices_when_too_many_options(self):
          mock_interaction = mock.AsyncMock(options=[mock.Mock(is_focused=True)])
          context = tanjun.context.AutocompleteContext(mock.Mock(tanjun.Client), mock_interaction)
  
          with pytest.raises(ValueError, match="Cannot set more than 25 choices"):
              await context.set_choices({str(v): "a" for v in range(0, 23)}, foo="ok", bar="as", baz="43")
  
          mock_interaction.create_response.assert_not_called()
  
      @pytest.mark.asyncio()
      async def test_set_choices_when_has_responded(self):
          mock_interaction = mock.AsyncMock(options=[mock.Mock(is_focused=True)])
          context = tanjun.context.AutocompleteContext(mock.Mock(tanjun.Client), mock_interaction)
          await context.set_choices()
          mock_interaction.create_response.reset_mock()
  
          with pytest.raises(RuntimeError, match="Cannot set choices after responding"):
              await context.set_choices()
  
          mock_interaction.create_response.assert_not_called()
  