text: # -*- coding: utf-8 -*-
  
  """
  jishaku.features.root_command
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
  The jishaku root command.
  
  :copyright: (c) 2021 Devon (Gorialis) R
  :license: MIT, see LICENSE for more details.
  
  """
  
  import math
  import sys
  import typing
  
  import discord
  from discord.ext import commands
  
  from jishaku.features.baseclass import Feature
  from jishaku.flags import Flags
  from jishaku.modules import package_version
  from jishaku.paginators import PaginatorInterface
  
  try:
      import psutil
  except ImportError:
      psutil = None
      
  
  def natural_size(size_in_bytes: int):
      """
      Converts a number of bytes to an appropriately-scaled unit
      E.g.:
          1024 -> 1.00 KiB
          12345678 -> 11.77 MiB
      """
      units = ('B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB')
  
      power = int(math.log(size_in_bytes, 1024))
  
      return f"{size_in_bytes / (1024 ** power):.2f} {units[power]}"
  
  
  class RootCommand(Feature):
      """
      Feature containing the root jsk command
      """
  
      def __init__(self, *args, **kwargs):
          super().__init__(*args, **kwargs)
          self.jsk.hidden = Flags.HIDE
  
      @Feature.Command(name="jishaku", aliases=["jsk"],
                       invoke_without_command=True, ignore_extra=False)
      async def jsk(self, ctx: commands.Context):
          """
          The Jishaku debug and diagnostic commands.
  
          This command on its own gives a status brief.
          All other functionality is within its subcommands.
          """
  
          summary = [
              f"Jishaku v{package_version('jishaku')}, discord.py `{package_version('discord.py')}`, "
              f"`Python {sys.version}` on `{sys.platform}`".replace("\n", ""),
              f"Module was loaded <t:{self.load_time.timestamp():.0f}:R>, "
              f"cog was loaded <t:{self.start_time.timestamp():.0f}:R>.",
              ""
          ]
  
          # detect if [procinfo] feature is installed
          if psutil:
              try:
                  proc = psutil.Process()
  
                  with proc.oneshot():
                      try:
                          mem = proc.memory_full_info()
                          summary.append(f"Using {natural_size(mem.rss)} physical memory and "
                                         f"{natural_size(mem.vms)} virtual memory, "
                                         f"{natural_size(mem.uss)} of which unique to this process.")
                      except psutil.AccessDenied:
                          pass
  
                      try:
                          name = proc.name()
                          pid = proc.pid
                          thread_count = proc.num_threads()
  
                          summary.append(f"Running on PID {pid} (`{name}`) with {thread_count} thread(s).")
                      except psutil.AccessDenied:
                          pass
  
                      summary.append("")  # blank line
              except psutil.AccessDenied:
                  summary.append(
                      "psutil is installed, but this process does not have high enough access rights "
                      "to query process information."
                  )
                  summary.append("")  # blank line
  
          cache_summary = f"{len(self.bot.guilds)} guild(s) and {len(self.bot.users)} user(s)"
  
          # Show shard settings to summary
          if isinstance(self.bot, discord.AutoShardedClient):
              if len(self.bot.shards) > 20:
                  summary.append(
                      f"This bot is automatically sharded ({len(self.bot.shards)} shards of {self.bot.shard_count})"
                      f" and can see {cache_summary}."
                  )
              else:
                  shard_ids = ', '.join(str(i) for i in self.bot.shards.keys())
                  summary.append(
                      f"This bot is automatically sharded (Shards {shard_ids} of {self.bot.shard_count})"
                      f" and can see {cache_summary}."
                  )
          elif self.bot.shard_count:
              summary.append(
                  f"This bot is manually sharded (Shard {self.bot.shard_id} of {self.bot.shard_count})"
                  f" and can see {cache_summary}."
              )
          else:
              summary.append(f"This bot is not sharded and can see {cache_summary}.")
  
          # pylint: disable=protected-access
          if self.bot._connection.max_messages:
              message_cache = f"Message cache capped at {self.bot._connection.max_messages}"
          else:
              message_cache = "Message cache is disabled"
  
          if discord.version_info >= (1, 5, 0):
              remarks = {
                  True: 'enabled',
                  False: 'disabled',
                  None: 'unknown'
              }
  
              *group, last = (
                  f"{intent.replace('_', ' ')} intent is {remarks.get(getattr(self.bot.intents, intent, None))}"
                  for intent in
                  ('presences', 'members', 'message_content')
              )
  
              summary.append(f"{message_cache}, {', '.join(group)}, and {last}.")
          else:
              guild_subscriptions = f"guild subscriptions are {'enabled' if self.bot._connection.guild_subscriptions else 'disabled'}"
  
              summary.append(f"{message_cache} and {guild_subscriptions}.")
  
          # pylint: enable=protected-access
  
          # Show websocket latency in milliseconds
          summary.append(f"Average websocket latency: {round(self.bot.latency * 1000, 2)}ms")
  
          await ctx.send("\n".join(summary))
  
      # pylint: disable=no-member
      @Feature.Command(parent="jsk", name="hide")
      async def jsk_hide(self, ctx: commands.Context):
          """
          Hides Jishaku from the help command.
          """
  
          if self.jsk.hidden:
              return await ctx.send("Jishaku is already hidden.")
  
          self.jsk.hidden = True
          await ctx.send("Jishaku is now hidden.")
  
      @Feature.Command(parent="jsk", name="show")
      async def jsk_show(self, ctx: commands.Context):
          """
          Shows Jishaku in the help command.
          """
  
          if not self.jsk.hidden:
              return await ctx.send("Jishaku is already visible.")
  
          self.jsk.hidden = False
          await ctx.send("Jishaku is now visible.")
      # pylint: enable=no-member
  
      @Feature.Command(parent="jsk", name="tasks")
      async def jsk_tasks(self, ctx: commands.Context):
          """
          Shows the currently running jishaku tasks.
          """
  
          if not self.tasks:
              return await ctx.send("No currently running tasks.")
  
          paginator = commands.Paginator(max_size=1980)
  
          for task in self.tasks:
              paginator.add_line(f"{task.index}: `{task.ctx.command.qualified_name}`, invoked at "
                                 f"{task.ctx.message.created_at.strftime('%Y-%m-%d %H:%M:%S')} UTC")
  
          interface = PaginatorInterface(ctx.bot, paginator, owner=ctx.author)
          return await interface.send_to(ctx)
  
      @Feature.Command(parent="jsk", name="cancel")
      async def jsk_cancel(self, ctx: commands.Context, *, index: typing.Union[int, str]):
          """
          Cancels a task with the given index.
  
          If the index passed is -1, will cancel the last task instead.
          """
  
          if not self.tasks:
              return await ctx.send("No tasks to cancel.")
  
          if index == "~":
              task_count = len(self.tasks)
  
              for task in self.tasks:
                  task.task.cancel()
  
              self.tasks.clear()
  
              return await ctx.send(f"Cancelled {task_count} tasks.")
  
          if isinstance(index, str):
              raise commands.BadArgument('Literal for "index" not recognized.')
  
          if index == -1:
              task = self.tasks.pop()
          else:
              task = discord.utils.get(self.tasks, index=index)
              if task:
                  self.tasks.remove(task)
              else:
                  return await ctx.send("Unknown task.")
  
          task.task.cancel()
          return await ctx.send(f"Cancelled task {task.index}: `{task.ctx.command.qualified_name}`,"
                                f" invoked at {task.ctx.message.created_at.strftime('%Y-%m-%d %H:%M:%S')} UTC")
  