# Ultroid - UserBot
# Copyright (C) 2021-2022 TeamUltroid
#
# This file is a part of < https://github.com/MrCode403/Jarves/ >
# PLease read the GNU Affero General Public License in
# <https://www.github.com/MrCode403/Jarves/blob/main/LICENSE/>.

"""
• `{i}akinator` | `/akinator`
   Start akinator game from Userbot/Assistant

• `/startgame`
   Open Portal for Games
"""

import asyncio
import operator
import re
import uuid
from html import unescape
from random import choice, shuffle

from . import LOGS

try:
    import akinator
except ImportError:
    akinator = None
    LOGS.error("'akinator' not installed.")

from telethon.errors.rpcerrorlist import (
    BotMethodInvalidError,
    ChatSendStickersForbiddenError,
)
from telethon.events import Raw
from telethon.tl.types import InputMediaPoll, Poll, PollAnswer, UpdateMessagePollVote

from pyJarves._misc._decorators import ultroid_cmd
from pyJarves.fns.helper import inline_mention
from pyJarves.fns.tools import async_searcher

from . import *

# -------------------------- Akinator ----------------------- #

games = {}
aki_photo = "https://graph.org/file/3cc8825c029fd0cab9edc.jpg"


@ultroid_cmd(pattern="akinator")
async def akina(e):
    if not akinator:
        return
    sta = akinator.Akinator()
    games.update({e.chat_id: {e.id: sta}})
    try:
        m = await e.client.inline_query(asst.me.username, f"aki_{e.chat_id}_{e.id}")
        await m[0].click(e.chat_id)
    except BotMethodInvalidError:
        await asst.send_file(
            e.chat_id,
            aki_photo,
            buttons=Button.inline(get_string("aki_2"), data=f"aki_{e.chat_id}_{e.id}"),
        )
    except Exception as er:
        return await e.eor(f"**ERROR :** `{er}`")
    if e.out:
        await e.delete()


@asst_cmd(pattern="akinator", owner=True)
async def _akokk(e):
    await akina(e)


@callback(re.compile("aki_(.*)"), owner=True)
async def doai(e):
    adt = e.pattern_match.group(1).strip().decode("utf-8")
    dt = adt.split("_")
    ch = int(dt[0])
    mid = int(dt[1])
    await e.edit(get_string("com_1"))
    try:
        qu = games[ch][mid].start_game(child_mode=True)
        # child mode should be promoted
    except KeyError:
        return await e.answer(get_string("aki_1"), alert=True)
    bts = [Button.inline(o, f"aka_{adt}_{o}") for o in ["Yes", "No", "Idk"]]
    cts = [Button.inline(o, f"aka_{adt}_{o}") for o in ["Probably", "Probably Not"]]

    bts = [bts, cts]
    # ignored Back Button since it makes the Pagination looks Bad
    await e.edit(f"Q. {qu}", buttons=bts)


@callback(re.compile("aka_(.*)"), owner=True)
async def okah(e):
    mk = e.pattern_match.group(1).decode("utf-8").split("_")
    ch = int(mk[0])
    mid = int(mk[1])
    ans = mk[2]
    try:
        gm = games[ch][mid]
    except KeyError:
        await e.answer(get_string("aki_3"))
        return
    text = gm.answer(ans)
    if gm.progression >= 80:
        gm.win()
        gs = gm.first_guess
        text = "It's " + gs["name"] + "\n " + gs["description"]
        return await e.edit(text, file=gs["absolute_picture_path"])
    bts = [Button.inline(o, f"aka_{ch}_{mid}_{o}") for o in ["Yes", "No", "Idk"]]
    cts = [
        Button.inline(o, f"aka_{ch}_{mid}_{o}") for o in ["Probably", "Probably Not"]
    ]

    bts = [bts, cts]
    await e.edit(text, buttons=bts)


@in_pattern(re.compile("aki_?(.*)"), owner=True)
async def eiagx(e):
    bts = Button.inline(get_string("aki_2"), data=e.text)
    ci = types.InputWebDocument(aki_photo, 0, "image/jpeg", [])
    ans = [
        await e.builder.article(
            "Akinator",
            type="photo",
            content=ci,
            text="Akinator",
            thumb=ci,
            buttons=bts,
            include_media=True,
        )
    ]
    await e.answer(ans)


# ----------------------- Main Command ------------------- #

GIMAGES = [
    "https://graph.org/file/1c51015bae5205a65fd69.jpg",
    "https://imgwhale.xyz/3xyr322l64j9590",
]


@asst_cmd(pattern="startgame", owner=True)
async def magic(event):
    buttons = [
        [Button.inline("Trivia Quiz", "trzia")],
        [Button.inline("Cancel ❌", "delit")],
    ]
    await event.reply(
        get_string("games_1"),
        file=choice(GIMAGES),
        buttons=buttons,
    )


# -------------------------- Trivia ----------------------- #

TR_BTS = {}
DIFI_KEYS = ["Easy", "Medium", "Hard"]
TRIVIA_CHATS = {}
POLLS = {}
CONGO_STICKER = [
    "CAADAgADSgIAAladvQrJasZoYBh68AI",
    "CAADAgADXhIAAuyZKUl879mlR_dkOwI",
    "CAADAgADpQAD9wLID-xfZCDwOI5LAg",
    "CAADAgADjAADECECEFZM-SrKO9GgAg",
    "CAADAgADSwIAAj-VzArAzNCDiGWAHAI",
    "CAADAgADhQADwZxgDIuMHR9IU10iAg",
    "CAADAgADiwMAAsSraAuoe2BwYu1sdQI",
]


@callback("delit", owner=True)
async def delete_it(event):
    await event.delete()


@callback(re.compile("ctdown(.*)"), owner=True)
async def ct_spam(e):
    n = e.data_match.group(1).decode("utf-8")
    await e.answer(f"Wait {n} seconds..", alert=True)


@callback(re.compile("trzia(.*)"), owner=True)
async def choose_cata(event):
    match = event.data_match.group(1).decode("utf-8")
    if not match:
        if TR_BTS.get("category"):
            buttons = TR_BTS["category"]
        else:
            req = (
                await async_searcher(
                    "https://opentdb.com/api_category.php", re_json=True
                )
            )["trivia_categories"]
            btt = []
            for i in req:
                name = i["name"]
                if ":" in name:
                    name = name.split(":")[1]
                btt.append(Button.inline(name, f"trziad_{i['id']}"))
            buttons = list(zip(btt[::2], btt[1::2]))
            if len(btt) % 2 == 1:
                buttons.append((btt[-1],))
            buttons.append([Button.inline("Cancel ❌", "delit")])
            TR_BTS.update({"category": buttons})
        text = get_string("games_2")
    elif match[0] == "d":
        cat = match[1:]
        buttons = [[Button.inline(i, f"trziac{cat}_{i}") for i in DIFI_KEYS]]
        buttons.append(get_back_button("trzia"))
        text = get_string("games_3")
    elif match[0] == "c":
        m = match[1:]
        buttons = [[Button.inline(str(i), f"trziat{m}_{i}") for i in range(10, 70, 20)]]
        text = get_string("games_4")
    elif match[0] == "t":
        m_ = match[1:]
        buttons = [
            [Button.inline(str(i), f"trzias{m_}_{i}") for i in [10, 30, 60, 120]]
        ]
        text = get_string("games_5")
    elif match[0] == "s":
        chat = event.chat_id
        cat, le, nu, in_ = match[2:].split("_")
        msg = await event.edit(get_string("games_6").format(le, nu))
        for i in reversed(range(5)):
            msg = await msg.edit(buttons=Button.inline(f"{i} ⏰", f"ctdown{i}"))
            await asyncio.sleep(1)
        await msg.edit(
            msg.text + "\n\n• Send /cancel to stop the Quiz...", buttons=None
        )
        qsss = await async_searcher(
            f"https://opentdb.com/api.php?amount={nu}&category={cat}&difficulty={le.lower()}",
            re_json=True,
        )
        qs = qsss["results"]
        if not qs:
            await event.respond("Sorry, No Question Found for the given Criteria..")
            await event.delete()
            return
        TRIVIA_CHATS.update({chat: {}})
        for copper, q in enumerate(qs):
            if TRIVIA_CHATS[chat].get("cancel") is not None:
                break
            ansi = str(uuid.uuid1()).split("-")[0].encode()
            opts = [PollAnswer(unescape(q["correct_answer"]), ansi)]
            [
                opts.append(
                    PollAnswer(unescape(a), str(uuid.uuid1()).split("-")[0].encode())
                )
                for a in q["incorrect_answers"]
            ]
            shuffle(opts)
            poll = InputMediaPoll(
                Poll(
                    0,
                    f"[{copper+1}].  " + unescape(q["question"]),
                    answers=opts,
                    public_voters=True,
                    quiz=True,
                    close_period=int(in_),
                ),
                correct_answers=[ansi],
                solution="Join @TeamUltroid",
                solution_entities=[],
            )
            m_ = await event.client.send_message(chat, file=poll)
            POLLS.update({m_.poll.poll.id: {"chat": m_.chat_id, "answer": ansi}})
            await asyncio.sleep(int(in_))
        if not TRIVIA_CHATS[chat]:
            await event.respond(
                "No-One Got Any Score in the Quiz!\nBetter Luck Next Time!"
            )
        else:
            try:
                await event.respond(file=choice(CONGO_STICKER))
            except ChatSendStickersForbiddenError:
                pass
            LBD = "🎯 **Scoreboard of the Quiz.**\n\n"
            TRC = TRIVIA_CHATS[chat]
            if "cancel" in TRC.keys():
                del TRC["cancel"]
            for userid, user_score in dict(
                sorted(TRC.items(), key=operator.itemgetter(1), reverse=True)
            ).items():
                user = inline_mention(await event.client.get_entity(userid))
                LBD += f"••• {user} - {user_score}\n"
            await event.respond(LBD)
        del TRIVIA_CHATS[chat]
        list_ = list(POLLS.copy().keys())
        for key in list_:
            if POLLS[key]["chat"] == chat:
                del POLLS[key]
        return
    await event.edit(text, buttons=buttons)


@asst.on(
    Raw(UpdateMessagePollVote, func=lambda x: TRIVIA_CHATS and POLLS.get(x.poll_id))
)
async def pollish(eve):
    if POLLS.get(eve.poll_id)["chat"] not in TRIVIA_CHATS.keys():
        return
    if POLLS[eve.poll_id]["answer"] != eve.options[0]:
        return
    chat = POLLS.get(eve.poll_id)["chat"]
    user = eve.user_id
    if not TRIVIA_CHATS.get(chat, {}).get(user):
        TRIVIA_CHATS[chat][user] = 1
    else:
        TRIVIA_CHATS[chat][user] += 1


@asst_cmd("cancel", owner=True, func=lambda x: TRIVIA_CHATS.get(x.chat_id))
async def cancelish(event):
    chat = TRIVIA_CHATS.get(event.chat_id)
    chat.update({"cancel": True})
    await event.respond("Cancelled!")
