import discord
from discord.ext import commands

from geeksbot.imports.utils import Paginator, Book


class Tickets(commands.Cog):
    def __init__(self, bot):
        self.bot = bot

    @commands.command()
    async def request(self, ctx, *, message=None):
        if not ctx.guild:
            await ctx.send("This command must be run from inside a guild.")
            return

        if not message:
            await ctx.send("Please include a message containing your request")
            return

        if len(message) > 1000:
            await ctx.send(
                "Request is too long, please keep your request to less than 1000 characters."
            )
            return

        data = {
            "author": ctx.author.id,
            "message": ctx.message.id,
            "channel": ctx.channel.id,
            "content": message,
        }
        msg_resp = await self.bot.aio_session.get(
            f"{self.bot.api_base}/messages/{ctx.message.id}/wait/",
            headers=self.bot.auth_header,
        )
        if msg_resp.status == 404:
            error = await msg_resp.json()
            await ctx.send(error["details"])
            return

        resp = await self.bot.aio_session.post(
            f"{self.bot.api_base}/messages/{ctx.guild.id}/requests/",
            headers=self.bot.auth_header,
            json=data,
        )

        if resp.status == 201:
            admin_channel_resp = await self.bot.aio_session.get(
                f"{self.bot.api_base}/channels/{ctx.guild.id}/admin/",
                headers=self.bot.auth_header,
            )
            request = await resp.json()

            if admin_channel_resp.status == 200:
                admin_chan_data = await admin_channel_resp.json()
                msg = f""
                admin_roles_resp = await self.bot.aio_session.get(
                    f"{self.bot.api_base}/guilds/{ctx.guild.id}/roles/admin/",
                    headers=self.bot.auth_header,
                )
                if admin_roles_resp.status == 200:
                    admin_roles_data = await admin_roles_resp.json()
                    for role in admin_roles_data:
                        msg += f'{ctx.guild.get_role(int(role["id"])).mention} '
                msg += (
                    f"New Request ID: {request['id']} "
                    f"{ctx.author.mention} has requested assistance: \n"
                    f"```{request['content']}``` \n"
                    f"Requested at: {request['requested_at'].split('.')[0].replace('T', ' ')} GMT\n"
                    f"In {ctx.guild.get_channel(int(request['channel'])).name}"
                )
                admin_chan = ctx.guild.get_channel(int(admin_chan_data["id"]))
                await admin_chan.send(msg)
            await ctx.send(
                f"{ctx.author.mention} The admin have received your request.\n"
                f'If you would like to update or close your request please reference Request ID `{request["id"]}`'
            )

    @commands.command(aliases=["comment"])
    async def update(self, ctx, request_id=None, *, comment: str = None):
        try:
            request_id = int(request_id)
        except ValueError:
            await ctx.send(
                "Please include the ID of the request you would like to update as the first thing after the command."
            )
            return

        if not comment:
            await ctx.send(
                "There is nothing to update since you didn't include a message."
            )
            return

        data = {"author": ctx.author.id, "content": comment}

        comment_resp = await self.bot.aio_session.post(
            f"{self.bot.api_base}/messages/{ctx.guild.id}/requests/{request_id}/comments/",
            headers=self.bot.auth_header,
            json=data,
        )

        if comment_resp.status == 201:
            comment = await comment_resp.json()
            admin_channel_resp = await self.bot.aio_session.get(
                f"{self.bot.api_base}/channels/{ctx.guild.id}/admin/",
                headers=self.bot.auth_header,
            )

            if admin_channel_resp.status == 200:
                admin_channel_data = await admin_channel_resp.json()
                admin_channel = ctx.guild.get_channel(int(admin_channel_data["id"]))
                if admin_channel:
                    request_resp = await self.bot.aio_session.get(
                        f"{self.bot.api_base}/messages/{ctx.guild.id}/requests/{request_id}/",
                        headers=self.bot.auth_header,
                    )
                    pag = Paginator(self.bot, prefix="```md", suffix="```")
                    header = (
                        f"{ctx.author.mention} has commented on request {request_id}\n"
                    )
                    if request_resp.status == 200:
                        request = await request_resp.json()
                        requestor = await ctx.guild.fetch_member(int(request["author"]))
                        header += (
                            f'Original Request by {requestor.mention if requestor else "`User cannot be found`"}:\n'
                            f'```{request["content"]}```'
                        )
                        pag.set_header(header)

                        if request.get("comments"):
                            comments = request["comments"]
                            for comment in comments:
                                author = await ctx.guild.fetch_member(
                                    int(comment["author"])
                                )
                                pag.add(
                                    f'{author.display_name}: {comment["content"]}',
                                    keep_intact=True,
                                )
                        if ctx.author != requestor and requestor:
                            for page in pag.pages(page_headers=False):
                                await requestor.send(page)
                    book = Book(pag, (None, admin_channel, self.bot, ctx.message))
                    await book.create_book()
            await ctx.send(
                f"{ctx.author.mention} Your comment has been added to the request."
            )

    @commands.command(name="requests_list", aliases=["rl"])
    async def _requests_list(self, ctx, closed: str = ""):
        pag = Paginator(self.bot)
        admin_roles_resp = await self.bot.aio_session.get(
            f"{self.bot.api_base}/guilds/{ctx.guild.id}/roles/admin/",
            headers=self.bot.auth_header,
        )
        if admin_roles_resp.status == 200:
            admin_roles_data = await admin_roles_resp.json()
            admin_roles = [
                ctx.guild.get_role(int(role["id"])) for role in admin_roles_data
            ]
            if any([role in ctx.author.roles for role in admin_roles]):
                requests_resp = await self.bot.aio_session.get(
                    f"{self.bot.api_base}/messages/{ctx.guild.id}/requests/",
                    headers=self.bot.auth_header,
                )
                if requests_resp.status == 200:
                    requests_data = await requests_resp.json()
                    requests_list = (
                        requests_data["requests"]
                        if isinstance(requests_data, dict)
                        else requests_data
                    )
                    while isinstance(requests_data, dict) and requests_data.get("next"):
                        requests_resp = await self.bot.aio_session.get(
                            requests_data["next"], headers=self.bot.auth_header
                        )
                        if requests_resp.status == 200:
                            requests_data = await requests_resp.json()
                            requests_list.extend(
                                requests_data["requests"]
                                if isinstance(requests_data, dict)
                                else requests_data
                            )
                    for request in requests_list:
                        member = await ctx.guild.fetch_member(int(request["author"]))
                        title = (
                            f"<{'Request ID':^20} {'Requested By':^20}>\n"
                            f"<{request['id']:^20} {member.display_name if member else 'None':^20}>"
                        )
                        orig_channel = ctx.guild.get_channel(
                            int(request.get("channel"))
                        )
                        comments_count_resp = await self.bot.aio_session.get(
                            f'{self.bot.api_base}/messages/{ctx.guild.id}/requests/{request["id"]}/comments/count/',
                            headers=self.bot.auth_header,
                        )
                        pag.add(
                            f"\n\n{title}\n"
                            f"{request['content']}\n\n"
                            f"Comments: {await comments_count_resp.text() if comments_count_resp.status == 200 else 0}\n"
                            f"Requested at: "
                            f"{request['requested_at'].split('.')[0].replace('T', ' ')} GMT\n"
                            f"In {orig_channel.name if orig_channel else 'N/A'}",
                            keep_intact=True,
                        )
                    pag.add(
                        f"\n\uFFF8\nThere are currently {len(requests_list)} requests open."
                    )
                else:
                    pag.add(
                        "There are no open requests for this guild.", keep_intact=True
                    )
            else:
                requests_resp = await self.bot.aio_session.get(
                    f"{self.bot.api_base}/messages/{ctx.guild.id}/requests/user/{ctx.author.id}/",
                    headers=self.bot.auth_header,
                )
                if requests_resp.status == 200:
                    requests_data = await requests_resp.json()
                    requests_list = (
                        requests_data["requests"]
                        if isinstance(requests_data, dict)
                        else requests_data
                    )
                    while isinstance(requests_data, dict) and requests_data.get("next"):
                        requests_resp = await self.bot.aio_session.get(
                            requests_data["next"], headers=self.bot.auth_header
                        )
                        if requests_resp.status == 200:
                            requests_data = await requests_resp.json()
                            requests_list.extend(
                                requests_data["requests"]
                                if isinstance(requests_data, dict)
                                else requests_data
                            )
                    for request in requests_list:
                        title = f"<{'Request ID':^20}>\n" f"<{request['id']:^20}>"
                        orig_channel = ctx.guild.get_channel(
                            int(request.get("channel"))
                        )
                        comments_count_resp = await self.bot.aio_session.get(
                            f'{self.bot.api_base}/messages/{ctx.guild.id}/requests/{request["id"]}/comments/count/',
                            headers=self.bot.auth_header,
                        )
                        pag.add(
                            f"\n\n{title}\n"
                            f"{request['content']}\n\n"
                            f"Comments: {await comments_count_resp.text() if comments_count_resp.status == 200 else 0}\n"
                            f"Requested at: "
                            f"{request['requested_at'].split('.')[0].replace('T', ' ')} GMT\n"
                            f"In {orig_channel.name if orig_channel else 'N/A'}",
                            keep_intact=True,
                        )
                    pag.add(
                        f"\n\uFFF8\nYou currently have {len(requests_list)} requests open."
                    )
                else:
                    pag.add(
                        "You have no open requests for this guild.", keep_intact=True
                    )
        for page in pag.pages():
            await ctx.send(page)

    @commands.command()
    async def close(self, ctx, *, ids=None):
        if not ids:
            await ctx.send("Please include at least one Request ID to close.")
            return

        admin = False
        admin_roles_resp = await self.bot.aio_session.get(
            f"{self.bot.api_base}/guilds/{ctx.guild.id}/roles/admin/",
            headers=self.bot.auth_header,
        )
        if admin_roles_resp.status == 200:
            admin_roles_data = await admin_roles_resp.json()
            admin_roles = [
                ctx.guild.get_role(int(role["id"])) for role in admin_roles_data
            ]
            if any([role in ctx.author.roles for role in admin_roles]):
                admin = True

        ids = [id.strip() for id in ids.replace(" ", "").split(",")]

        for id in ids:
            request_resp = await self.bot.aio_session.get(
                f"{self.bot.api_base}/messages/{ctx.guild.id}/requests/{id}/",
                headers=self.bot.auth_header,
            )
            if request_resp.status == 200:
                request = await request_resp.json()
                requestor = await ctx.guild.fetch_member(int(request["author"]))
                if requestor == ctx.author or admin:
                    data = {"completed_by": ctx.author.id}
                    delete_resp = await self.bot.aio_session.delete(
                        f"{self.bot.api_base}/messages/{ctx.guild.id}/requests/{id}/",
                        headers=self.bot.auth_header,
                        json=data,
                    )
                    if delete_resp.status == 202:
                        delete_data = await delete_resp.json()
                        if delete_data["completed"]:
                            await ctx.send(f"Request {id} closed.")
                            await requestor.send(
                                f"{ctx.author.display_name} has closed request {id} which was "
                                f"opened by you in the "
                                f'{ctx.guild.get_channel(int(request["channel"])).name} '
                                f"channel."
                                f'```{request["content"]}```'
                                f"If there are any issues please open a new request."
                            )
                else:
                    await ctx.send("That is not your request to close.")

    @commands.command()
    async def view(self, ctx, id=None):
        if not id:
            await ctx.send(
                "Please include the id of the request you would like to view."
            )
            return

        admin = False
        admin_roles_resp = await self.bot.aio_session.get(
            f"{self.bot.api_base}/guilds/{ctx.guild.id}/roles/admin/",
            headers=self.bot.auth_header,
        )
        if admin_roles_resp.status == 200:
            admin_roles_data = await admin_roles_resp.json()
            admin_roles = [
                ctx.guild.get_role(int(role["id"])) for role in admin_roles_data
            ]
            if any([role in ctx.author.roles for role in admin_roles]):
                admin = True

        request_resp = await self.bot.aio_session.get(
            f"{self.bot.api_base}/messages/{ctx.guild.id}/requests/{id}/",
            headers=self.bot.auth_header,
        )
        if request_resp.status == 200:
            request = await request_resp.json()
            requestor = await ctx.guild.fetch_member(int(request["author"]))
            if requestor == ctx.author or admin:
                pag = Paginator(self.bot, prefix="```md", suffix="```")
                header = (
                    f'Request {id} by {requestor.mention if requestor else "`User cannot be found`"}:\n'
                    f'```{request["content"]}```'
                )
                pag.set_header(header)

                if request.get("comments"):
                    pag.add("Comments: \n")
                    comments = request["comments"]
                    for comment in comments:
                        author = await ctx.guild.fetch_member(int(comment["author"]))
                        pag.add(
                            f'{author.display_name}: {comment["content"]}',
                            keep_intact=True,
                        )
                else:
                    pag.add("No Comments")

                if request.get("completed"):
                    closer = await ctx.guild.fetch_member(
                        int(request.get("completed_by"))
                    )
                    pag.add(
                        f'Closed By: {closer.name}#{closer.discriminator}\n{request.get("completed_message")}'
                    )
                book = Book(pag, (None, ctx.channel, self.bot, ctx.message))
                await book.create_book()
            else:
                await ctx.send("That is not your request to close.")


def setup(bot):
    bot.add_cog(Tickets(bot))
