import random
import re
from typing import Callable
from urllib import parse

from qutebrowser.api import interceptor
from qutebrowser.extensions.interceptors import QUrl, RedirectException
from qutebrowser.utils import message


def fixScribePath(url: QUrl):
    """Fix external medium blog to scribe translation.
    Some paths from medium will go through a 'global identity'
    path which messes up the actual url path we want to go
    to and puts it in queries. This puts it back on the path.
    """
    # double unquoting necessary!
    # I suppose we double-wrap it earlier somewhere?
    # unquoted = parse.unquote(
    #     url.path(options=QUrl.ComponentFormattingOption.FullyEncoded)
    # )
    path = parse.unquote(f"{url.path()}{url.query()}", encoding="ascii")
    url.setQuery(None)
    new_path = re.sub(r"m/global-identity-2redirectUrl=", "", path)
    url.setPath(
        parse.quote(new_path),
        mode=QUrl.ParsingMode.StrictMode,
    )
    return url


type Service = dict[str, list[str]]
type Redirects = dict[str, Service]


redirects: Redirects = {
    "youtube": {
        "source": ["youtube.com"],
        "farside": ["invidious"],
    },
    "stackoverflow": {
        "source": ["stackoverflow.com", "askubuntu.com"],
        "farside": ["anonymousoverflow"],
    },
    "lbry": {
        "source": ["odysee.com"],
        "farside": ["librarian"],
    },
    "reddit": {
        "source": ["reddit.com"],
        "farside": ["redlib"],
    },
    "instagram": {
        "source": ["instagram.com"],
        "farside": ["proxigram"],
    },
    "twitter": {
        "source": ["twitter.com"],
        "farside": ["nitter"],
    },
    "imdb": {
        "source": ["imdb.com"],
        "farside": ["libremdb"],
    },
    "translate": {
        "source": ["translate.google.com"],
        "farside": ["lingva"],
    },
    "tiktok": {
        "source": ["tiktok.com"],
        "farside": ["proxitok"],
    },
    "imgur": {
        "source": ["imgur.com"],
        "farside": ["rimgo"],
    },
    "medium": {
        "source": ["medium.com"],
        "farside": ["scribe"],
        # "postprocess": fixScribePath
    },
    "fandom": {
        "source": ["fandom.com"],
        "farside": ["breezewiki"],
    },
    "quora": {
        "source": ["quora.com"],
        "farside": ["quetre"],
        # "postprocess": lambda url: message.info(f"CALLING QUORA WITH {url}")
    },
    "google": {
        "source": ["google.com"],
        "target": [
            "search.albony.xyz",
            "search.garudalinux.org",
            "search.dr460nf1r3.org",
            "s.tokhmi.xyz",
            "search.sethforprivacy.com",
            "whoogle.dcs0.hu",
            "gowogle.voring.me",
            "whoogle.privacydev.net",
            "wg.vern.cc",
            "whoogle.hxvy0.gq",
            "whoogle.hostux.net",
            "whoogle.lunar.icu",
            "wgl.frail.duckdns.org",
            "whoogle.no-logs.com",
            "whoogle.ftw.lol",
            "whoogle-search--replitcomreside.repl.co",
            "search.notrustverify.ch",
            "whoogle.datura.network",
            "whoogle.yepserver.xyz",
            "search.nezumi.party",
        ],
    },
    "biblioreads": {
        "source": ["goodreads.com"],
        "target": [
            "biblioreads.eu.org",
            "biblioreads.vercel.app",
            "biblioreads.mooo.com",
            "bl.vern.cc",
            "biblioreads.lunar.icu",
            "read.whateveritworks.org",
            "biblioreads.privacyfucking.rocks",
            "read.seitan-ayoub.lol",
            "read.freedit.eu",
            "biblioreads.ducks.party",
            "biblioreads.snine.nl",
            "biblioreads.privacyredirect.com",
        ],
    },
    "safetwitch": {
        "source": ["twitch.tv"],
        "target": [
            "safetwitch.drgns.space",
            "safetwitch.projectsegfau.lt",
            "stream.whateveritworks.org",
            "safetwitch.datura.network",
            "ttv.vern.cc",
            "safetwitch.frontendfriendly.xyz",
            "ttv.femboy.band",
            "twitch.seitan-ayoub.lol",
            "st.ggtyler.dev",
            "safetwitch.lunar.icu",
            "twitch.sudovanilla.com",
            "safetwitch.r4fo.com",
            "safetwitch.ducks.party",
            "safetwitch.nogafam.fr",
            "safetwitch.privacyredirect.com",
            "st.ngn.tf",
        ],
    },
}


def rewrite(request: interceptor.Request) -> None:
    # if config.get(name="content.oss_redirects") is False:
    #     return

    if (
        request.resource_type != interceptor.ResourceType.main_frame
        or request.request_url.scheme() in {"data", "blob"}
    ):
        return

    url = request.request_url

    if service := _should_be_redirected(url.host()):
        url = _farside_redirect(
            url, _pick_random(service["farside" if "farside" in service else "target"])
        )
        try:
            request.redirect(url)
        except RedirectException as e:
            message.error(str(e))

        if "postprocess" in service and isinstance(service["postprocess"], Callable):
            url = service["postprocess"](url)


def _farside_redirect(url: QUrl, service: str, use_fastside: bool = True) -> QUrl:
    try:
        url.setHost("fastside.link" if use_fastside else "farside.link")
        url.setPath(f"/{service}{url.path()}")
    except RedirectException as e:
        message.error(str(e))
    return url


def _pick_random[T](choices: list[T]) -> T:
    return choices[random.randint(0, len(choices) - 1)]


def _should_be_redirected(
    # TODO: Update to use typedefs/classes instead of this jumble
    host: str,
    redirects: Redirects = redirects,
) -> Service | None:
    for service in redirects.values():
        for source in service["source"]:
            if re.search(source, host):
                return service
    return None


interceptor.register(rewrite)
