import re
import base64
import json
from urllib.request import Request, urlopen
from urllib.error import HTTPError, URLError

import requests
from bs4 import BeautifulSoup

from aniworld import config


def shift_letters(input_str):
    result = ''
    for c in input_str:
        code = ord(c)
        if 65 <= code <= 90:
            code = (code - 65 + 13) % 26 + 65
        elif 97 <= code <= 122:
            code = (code - 97 + 13) % 26 + 97
        result += chr(code)
    return result


def replace_junk(input_str):
    junk_parts = ['@$', '^^', '~@', '%?', '*~', '!!', '#&']
    for part in junk_parts:
        input_str = re.sub(re.escape(part), '_', input_str)
    return input_str


def shift_back(s, n):
    return ''.join(chr(ord(c) - n) for c in s)


def decode_voe_string(encoded):
    step1 = shift_letters(encoded)
    step2 = replace_junk(step1).replace('_', '')
    step3 = base64.b64decode(step2).decode()
    step4 = shift_back(step3, 3)
    step5 = base64.b64decode(step4[::-1]).decode()
    return json.loads(step5)


def extract_voe_from_script(html):
    soup = BeautifulSoup(html, "html.parser")
    script = soup.find("script", type="application/json")
    return decode_voe_string(script.text[2:-2])["source"]


def get_direct_link_from_voe(embeded_voe_link: str) -> str:
    response = requests.get(
        embeded_voe_link,
        headers={'User-Agent': config.RANDOM_USER_AGENT},
        timeout=config.DEFAULT_REQUEST_TIMEOUT
    )

    redirect = re.search(r"https?://[^'\"<>]+", response.text)
    if not redirect:
        raise ValueError("No redirect found.")

    redirect_url = redirect.group(0)
    parts = redirect_url.strip().split("/")
    config.PROVIDER_HEADERS["VOE"].append(
        f'Referer: "{parts[0]}//{parts[2]}/"')

    try:
        with urlopen(
            Request(
                redirect_url,
                headers={'User-Agent': config.RANDOM_USER_AGENT}
            ),
            timeout=config.DEFAULT_REQUEST_TIMEOUT
        ) as resp:
            html = resp.read().decode()
    except (HTTPError, URLError, TimeoutError) as err:
        raise ValueError(f"Redirect failed: {err}") from err

    extracted = extract_voe_from_script(html)
    if extracted:
        return extracted

    b64match = re.search(r"var a168c='([^']+)'", html)
    if b64match:
        decoded = base64.b64decode(b64match.group(1)).decode()[::-1]
        return json.loads(decoded)["source"]

    hls = re.search(r"'hls': '(?P<hls>[^']+)'", html)
    if hls:
        return base64.b64decode(hls.group("hls")).decode()

    raise ValueError(
        "Unable to process this VOE link.\n\n"
        "Try using a different provider for now.\n"
        "If this issue persists and hasn't been reported yet, please consider creating a new issue."
    )


if __name__ == '__main__':
    link = input("Enter VOE Link: ")
    print(get_direct_link_from_voe(link))
