import io

import aiohttp
import discord
from colorthief import ColorThief
from red_commons.logging import RedTraceLogger, getLogger
from redbot.core import app_commands, commands
from redbot.core.bot import Red
from redbot.core.utils.chat_formatting import bold, humanize_list

from .model import PartialEmoji


class EmojiInfo(commands.Cog):
    """Retrieve information about emojis."""

    __author__ = ["[cswimr](https://www.coastalcommits.com/cswimr)"]
    __git__ = "https://www.coastalcommits.com/cswimr/SeaCogs"
    __version__ = "1.0.3"
    __documentation__ = "https://seacogs.coastalcommits.com/emojiinfo/"

    def __init__(self, bot: Red) -> None:
        super().__init__()
        self.bot: Red = bot
        self.logger: RedTraceLogger = getLogger(name="red.SeaCogs.EmojiInfo")

    def format_help_for_context(self, ctx: commands.Context) -> str:
        pre_processed = super().format_help_for_context(ctx) or ""
        n = "\n" if "\n\n" not in pre_processed else ""
        text = [
            f"{pre_processed}{n}",
            f"{bold('Cog Version:')} [{self.__version__}]({self.__git__})",
            f"{bold('Author:')} {humanize_list(self.__author__)}",
            f"{bold('Documentation:')} {self.__documentation__}",
        ]
        return "\n".join(text)

    async def fetch_twemoji(self, unicode_emoji) -> str:
        base_url = "https://cdn.jsdelivr.net/gh/jdecked/twemoji@latest/assets/72x72/"
        emoji_codepoint = "-".join([hex(ord(char))[2:] for char in unicode_emoji])
        segments = emoji_codepoint.split("-")
        valid_segments = [seg for seg in segments if len(seg) >= 4]
        return f"{base_url}{valid_segments[0]}.png"

    async def fetch_primary_color(self, emoji_url: str) -> discord.Color | None:
        async with aiohttp.ClientSession() as session:
            async with session.get(emoji_url) as response:
                if response.status != 200:
                    return None
                image = await response.read()
        dominant_color = ColorThief(io.BytesIO(image)).get_color(quality=1)
        return discord.Color.from_rgb(*dominant_color)

    async def get_emoji_info(self, emoji: PartialEmoji) -> tuple[str, str]:
        if emoji.is_unicode_emoji():
            try:
                emoji_url = await self.fetch_twemoji(unicode_emoji=emoji.name)
            except IndexError as e:
                raise e
        else:
            emoji_url = emoji.url

        if emoji.id is not None:
            emoji_id = f"{bold('ID:')} `{emoji.id}`\n"
            markdown = f"`<{'a' if emoji.animated else ''}:{emoji.name}:{emoji.id}>`"
            name = f"{bold('Name:')} {emoji.name}\n"
            aliases = ""
            group = ""
        else:
            emoji_id = ""
            markdown = f"`{emoji}`"
            name = f"{bold('Name:')} {emoji.aliases.pop(0) if emoji.aliases else emoji.name}\n"
            aliases = f"{bold('Aliases:')} {', '.join(emoji.aliases)}\n" if emoji.aliases else ""
            group = f"{bold('Group:')} {emoji.group}\n"

        return (f"{name}{emoji_id}{bold('Native:')} {emoji.is_unicode_emoji()}\n{group}{aliases}{bold('Animated:')} {emoji.animated}\n{bold('Markdown:')} {markdown}\n{bold('URL:')} [Click Here]({emoji_url})"), emoji_url

    @app_commands.command(name="emoji")
    @app_commands.describe(emoji="What emoji would you like to get information on?", ephemeral="Would you like the response to be hidden?")
    async def emoji_slash(self, interaction: discord.Interaction, emoji: str, ephemeral: bool = True) -> None:
        """Retrieve information about an emoji."""
        await interaction.response.defer(ephemeral=ephemeral)

        try:
            retrieved_emoji: PartialEmoji = PartialEmoji.from_str(self, value=emoji)
            string, emoji_url = await self.get_emoji_info(retrieved_emoji)
            self.logger.verbose(f"Emoji:\n{string}")
        except (IndexError, UnboundLocalError):
            return await interaction.followup.send("Please provide a valid emoji!")

        assert isinstance(interaction.channel, discord.TextChannel)
        if await self.bot.embed_requested(channel=interaction.channel):
            embed = discord.Embed(title="Emoji Information", description=string, color=await self.fetch_primary_color(emoji_url) or await self.bot.get_embed_color(interaction.channel))
            embed.set_thumbnail(url=emoji_url)

            await interaction.followup.send(embed=embed)
            return None
        await interaction.followup.send(content=string)
        return None

    @commands.command(name="emoji")
    async def emoji(self, ctx: commands.Context, *, emoji: str) -> None:
        """Retrieve information about an emoji."""
        try:
            retrieved_emoji: PartialEmoji = PartialEmoji.from_str(self, value=emoji)
            string, emoji_url = await self.get_emoji_info(retrieved_emoji)
            self.logger.verbose(f"Emoji:\n{string}")
        except (IndexError, UnboundLocalError):
            await ctx.send("Please provide a valid emoji!")
            return

        if await ctx.embed_requested():
            embed = discord.Embed(title="Emoji Information", description=string, color=await self.fetch_primary_color(emoji_url) or await ctx.embed_color())
            embed.set_thumbnail(url=emoji_url)

            await ctx.send(embed=embed)
            return
        await ctx.send(content=string)
        return