################################################################
"""
 Mix-Userbot Open Source . Maintained ? Yes Oh No Oh Yes Ngentot
 
 @ CREDIT : NAN-DEV
"""
################################################################

from asyncio import QueueEmpty
from base64 import urlsafe_b64decode
from struct import unpack

from attrify import Attrify as Atr
from pytgcalls.exceptions import NoActiveGroupCall, NotInGroupCallError
from pytgcalls.types import StreamAudioEnded, Update

from Mix import user
from team.nandev import queues

from asyncio import get_event_loop
from functools import partial
from json import dumps, loads
from urllib.parse import quote_plus

from requests import get
from yt_dlp import YoutubeDL

daftar_join = []


def unpackInlineMessage(inline_message_id: str):
    dc_id, message_id, chat_id, query_id = unpack(
        "<iiiq",
        urlsafe_b64decode(
            inline_message_id + "=" * (len(inline_message_id) % 4),
        ),
    )
    temp = {
        "dc_id": dc_id,
        "message_id": message_id,
        "chat_id": int(str(chat_id).replace("-1", "-1001")),
        "query_id": query_id,
        "inline_message_id": inline_message_id,
    }
    return Atr(temp)



@user.pytgc_dec()
async def _(_, m: int):
    global turun_dewek
    if m in daftar_join:
        turun_dewek = False
    else:
        try:
            queues.clear(m)
            turun_dewek = True
        except QueueEmpty:
            pass


@user.pytgc_dec()
async def _(c, u: Update):
    global turun_dewek
    if isinstance(u, StreamAudioEnded):
        queues.task_done(u.chat_id)
        if u.chat_id in daftar_join:
            turun_dewek = False
        elif queues.is_empty(u.chat_id):
            try:
                await c.leave_group_call(u.chat_id)
                turun_dewek = True
            except (NotInGroupCallError, NoActiveGroupCall):
                pass
        else:
            await c.change_stream(
                u.chat_id, queues.get(u.chat_id)["file"]
            )


def run_sync(func, *args, **kwargs):
    return get_event_loop().run_in_executor(None, partial(func, *args, **kwargs))


async def YoutubeDownload(url, as_video=False):
    if as_video:
        ydl_opts = {
            "quiet": True,
            "no_warnings": True,
            "format": "(bestvideo[height<=?720][width<=?1280][ext=mp4])+(bestaudio[ext=m4a])",
            "outtmpl": "downloads/%(id)s.%(ext)s",
            "nocheckcertificate": True,
            "geo_bypass": True,
        }
    else:
        ydl_opts = {
            "quiet": True,
            "no_warnings": True,
            "format": "bestaudio[ext=m4a]",
            "outtmpl": "downloads/%(id)s.%(ext)s",
            "nocheckcertificate": True,
            "geo_bypass": True,
        }
    data_ytp = "<b>💡 Informasi {}</b>\n\n<b>🏷 Nama:</ʙ> {}<b>\n<b>🧭 Durasi:</b> {}\n<b>👀 Dilihat:</b> {}\n<b>📢 Channel:</b> {}\n<b>🔗 Tautan:</b> <a href={}>Youtube</a>\n\n<b>⚡ Download By:</b> {}"
    ydl = YoutubeDL(ydl_opts)
    ytdl_data = await run_sync(ydl.extract_info, url, download=True)
    file_name = ydl.prepare_filename(ytdl_data)
    videoid = ytdl_data["id"]
    title = ytdl_data["title"]
    url = f"https://youtu.be/{videoid}"
    duration = ytdl_data["duration"]
    channel = ytdl_data["uploader"]
    views = f"{ytdl_data['view_count']:,}".replace(",", ".")
    thumb = f"https://img.youtube.com/vi/{videoid}/hqdefault.jpg"
    return file_name, title, url, duration, views, channel, thumb, data_ytp


class YouTubeSearch:
    def __init__(self, search_terms: str, max_results=None):
        self.search_terms = search_terms
        self.max_results = max_results
        self.videos = self._search()

    def _search(self):
        encoded_search = quote_plus(self.search_terms)
        url = f"https://www.youtube.com/results?search_query={encoded_search}"
        response = get(url).text
        while "ytInitialData" not in response:
            response = get(url).text
        results = self._parse_html(response)
        if self.max_results is not None and len(results) > self.max_results:
            return results[: self.max_results]
        return results

    @staticmethod
    def _parse_html(response):
        results = []
        start = response.index("ytInitialData") + len("ytInitialData") + 3
        end = response.index("};", start) + 1
        json_str = response[start:end]
        data = loads(json_str)

        for contents in data["contents"]["twoColumnSearchResultsRenderer"][
            "primaryContents"
        ]["sectionListRenderer"]["contents"]:
            for video in contents["itemSectionRenderer"]["contents"]:
                res = {}
                if "videoRenderer" in video.keys():
                    video_data = video.get("videoRenderer", {})
                    res["id"] = video_data.get("videoId", None)
                    res["title"] = (
                        video_data.get("title", {})
                        .get("runs", [[{}]])[0]
                        .get("text", None)
                    )
                    res["duration"] = video_data.get("lengthText", {}).get(
                        "simpleText", 0
                    )
                    res["views"] = video_data.get("viewCountText", {}).get(
                        "simpleText", 0
                    )
                    res["link"] = "https://www.youtube.com" + (
                        video_data.get("navigationEndpoint", {})
                        .get("commandMetadata", {})
                        .get("webCommandMetadata", {})
                        .get("url", None)
                    )
                    if (
                        res["duration"] != 0
                        and res["views"] != 0
                        and sum(
                            int(x) * 60**i
                            for i, x in enumerate(
                                reversed(str(res["duration"]).split(":"))
                            )
                        )
                        < 7200
                    ):
                        results.append(res)

            if results:
                return results
        return results

    def to_dict(self, clear_cache=True):
        result = self.videos
        if clear_cache:
            self.videos = ""
        return result

    def to_json(self, clear_cache=True):
        result = dumps({"videos": self.videos})
        if clear_cache:
            self.videos = ""
        return result
