import contextlib

from xbmcgui import DialogProgress

from lib.utils.general.utils import supported_video_extensions
from lib.utils.kodi.utils import dialogyesno, notification, translation
from lib.utils.kodi.utils import sleep as ksleep

DEBRID_ERROR_STATUS = ("magnet_error", "error", "virus", "dead")


def run_realdebrid_download(client, magnet_url, pack=False):
    interval = 5
    cancelled = False
    response = client.add_magnet_link(magnet_url)
    if not response:
        return

    torrent_id = response["id"]
    progress_dialog = DialogProgress()
    torrent_info = client.get_torrent_info(torrent_id)
    if not torrent_info:
        return

    status = torrent_info["status"]
    if status == "magnet_conversion":
        msg = translation(90638) % torrent_info["filename"]
        progress_timeout = 100
        progress_dialog.create(translation(90565))
        while status == "magnet_conversion" and progress_timeout > 0:
            progress_dialog.update(progress_timeout, msg)
            if progress_dialog.iscanceled():
                cancelled = True
                break
            progress_timeout -= interval
            ksleep(1000 * interval)
            torrent_info = client.get_torrent_info(torrent_id)
            status = torrent_info["status"]
            if any(error in status for error in DEBRID_ERROR_STATUS):
                notification(translation(90639))
                break
    elif status == "downloaded":
        notification(translation(90640))
        return
    elif status == "waiting_files_selection":
        cancelled = _handle_waiting_file_selection(
            client, torrent_id, torrent_info, progress_dialog, interval, pack
        )

    with contextlib.suppress(Exception):
        progress_dialog.close()

    ksleep(500)
    if cancelled:
        response = dialogyesno(translation(32029), translation(90564))
        if response:
            notification(translation(90641))
        else:
            client.delete_torrent(torrent_id)


def _handle_waiting_file_selection(
    client, torrent_id, torrent_info, progress_dialog, interval, pack
):
    files = torrent_info["files"]
    extensions = supported_video_extensions()[:-1]
    items = [
        item
        for item in files
        for extension in extensions
        if item["path"].lower().endswith(extension)
    ]
    try:
        video = max(items, key=lambda item: item["bytes"])
        file_id = video["id"]
    except ValueError as error:
        notification(error)
        return False

    client.select_files(torrent_id, str(file_id))
    ksleep(2000)
    torrent_info = client.get_torrent_info(torrent_id)
    if not torrent_info:
        return False

    status = torrent_info["status"]
    if status == "downloaded":
        notification(translation(90642))
        return False

    file_size = round(float(video["bytes"]) / (1000**3), 2)
    msg = translation(90643) % torrent_info["filename"]
    progress_dialog.create(translation(90565))
    progress_dialog.update(1, msg)
    while status != "downloaded":
        ksleep(1000 * interval)
        torrent_info = client.get_torrent_info(torrent_id)
        status = torrent_info["status"]
        if status == "downloading":
            msg2 = translation(90644) % (
                file_size,
                round(float(torrent_info["speed"]) / (1000**2), 2),
                torrent_info["seeders"],
                torrent_info["progress"],
            )
        else:
            msg2 = status
        progress_dialog.update(int(float(torrent_info["progress"])), msg + msg2)
        try:
            if progress_dialog.iscanceled():
                return True
        except Exception:
            pass
        if any(error in status for error in DEBRID_ERROR_STATUS):
            notification(translation(90639))
            break
    return False
