# Mobile Verification Toolkit (MVT)
# Copyright (c) 2021-2023 The MVT Authors.
# Use of this software is governed by the MVT License 1.1 that can be found at
#   https://license.mvt.re/1.1/

import logging
from typing import Optional
from urllib.parse import urlparse

import requests
from tld import get_tld

from .config import settings

log = logging.getLogger(__name__)

SHORTENER_DOMAINS = [
    "0rz.tw",
    "1drv.ms",
    "1link.in",
    "1url.com",
    "2big.at",
    "2.gp",
    "2pl.us",
    "2tu.us",
    "2ya.com",
    "3.ly",
    "4sq.com",
    "4url.cc",
    "6url.com",
    "7.ly",
    "a2a.me",
    "abbrr.com",
    "adf.ly",
    "adjix.com",
    "a.gg",
    "alturl.com",
    "a.nf",
    "anon.to",
    "apple.news",
    "atu.ca",
    "b23.ru",
    "bacn.me",
    "bc.vc",
    "bfy.tw",
    "binged.it",
    "bit.do",
    "bit.ly",
    "bizj.us",
    "bkite.com",
    "bloat.me",
    "budurl.com",
    "buff.ly",
    "buk.me",
    "burnurl.com",
    "chilp.it",
    "chn.ge",
    "clck.ru",
    "clickmeter.com",
    "cli.gs",
    "c-o.in",
    "cort.as",
    "cut.ly",
    "cutt.ly",
    "cuturl.com",
    "dai.ly",
    "dailym.ai",
    "db.tt",
    "decenturl.com",
    "dfl8.me",
    "digbig.com",
    "digg.com",
    "disq.us",
    "dlvr.it",
    "doiop.com",
    "do.my",
    "dwarfurl.com",
    "dy.fi",
    "easyuri.com",
    "easyurl.net",
    "eepurl.com",
    "esyurl.com",
    "ewerl.com",
    "fa.b",
    "fa.by",
    "fb.me",
    "fff.to",
    "ff.im",
    "fhurl.com",
    "fire.to",
    "firsturl.de",
    "firsturl.net",
    "flic.kr",
    "flq.us",
    "fly2.ws",
    "fon.gs",
    "forms.gle",
    "fwd4.me",
    "gdurl.com",
    "gg.gg",
    "gl.am",
    "go2cut.com",
    "go2.me",
    "go.9nl.com",
    "goo.gl",
    "goshrink.com",
    "got.by",
    "gowat.ch",
    "gri.ms",
    "gurl.es",
    "hellotxt.com",
    "hex.io",
    "hongkiat.shorturl.com",
    "hover.com",
    "href.in",
    "ht.ly",
    "htxt.it",
    "hugeurl.com",
    "hurl.it",
    "hurl.me",
    "hurl.ws",
    "ibb.co",
    "icanhaz.com",
    "idek.net",
    "inreply.to",
    "iscool.net",
    "is.gd",
    "iterasi.net",
    "jijr.com",
    "j.mp",
    "jmp2.net",
    "just.as",
    "kissa.be",
    "kl.am",
    "klck.me",
    "korta.nu",
    "krunchd.com",
    "lat.ms",
    "liip.to",
    "liltext.com",
    "lin.cr",
    "linkbee.com",
    "linkbun.ch",
    "liurl.cn",
    "lnkd.in",
    "lnk.gd",
    "lnk.in",
    "ln-s.net",
    "ln-s.ru",
    "loopt.us",
    "lru.jp",
    "lt.tl",
    "lurl.no",
    "lyhyt.eu",
    "metamark.net",
    "migre.me",
    "minilien.com",
    "miniurl.com",
    "minurl.fr",
    "moourl.com",
    "myurl.in",
    "nbcnews.to",
    "ne1.net",
    "njx.me",
    "nn.nf",
    "notlong.com",
    "n.pr",
    "nsfw.in",
    "nyti.ms",
    "om.ly",
    "onforb.es",
    "on.mktw.net",
    "ow.ly",
    "o-x.fr",
    "pca.st",
    "pd.am",
    "pic.gd",
    "ping.fm",
    "piurl.com",
    "pnt.me",
    "politi.co",
    "poprl.com",
    "posted.at",
    "post.ly",
    "profile.to",
    "q.gs",
    "qicute.com",
    "qlnk.net",
    "qr.ae",
    "qte.me",
    "quip-art.com",
    "rb6.me",
    "rb.gy",
    "read.bi",
    "redir.ec",
    "redirx.com",
    "redr.me",
    "reut.rs",
    "rickroll.it",
    "r.im",
    "ri.ms",
    "riz.gd",
    "rsmonkey.com",
    "rubyurl.com",
    "ru.ly",
    "s7y.us",
    "safe.mn",
    "sharein.com",
    "sharetabs.com",
    "shorl.com",
    "short.ie",
    "shortlinks.co.uk",
    "shortna.me",
    "short.to",
    "shorturl.at",
    "shorturl.com",
    "shoturl.us",
    "shout.to",
    "shrinkify.com",
    "shrinkster.com",
    "shrten.com",
    "shrt.st",
    "shrunkin.com",
    "shw.me",
    "simurl.com",
    "smsh.me",
    "sn.im",
    "snipr.com",
    "snipurl.com",
    "snurl.com",
    "sp2.ro",
    "spedr.com",
    "sqrl.it",
    "starturl.com",
    "sturly.com",
    "su.pr",
    "t.cn",
    "t.co",
    "tcrn.ch",
    "tgr.ph",
    "thrdl.es",
    "tighturl.com",
    "tiny123.com",
    "tinyarro.ws",
    "tiny.cc",
    "tinylink.in",
    "tiny.pl",
    "tiny.tw",
    "tinytw.it",
    "tinyuri.ca",
    "tinyurl.com",
    "tinyvid.io",
    "t.me",
    "tnij.org",
    "tnw.to",
    "togoto.us",
    "to.ly",
    "traceurl.com",
    "tr.im",
    "tr.my",
    "turo.us",
    "tweetburner.com",
    "twirl.at",
    "twit.ac",
    "twitterpan.com",
    "twitthis.com",
    "twiturl.de",
    "twurl.cc",
    "twurl.nl",
    "u6e.de",
    "ub0.cc",
    "ukl.me.uk",
    "u.mavrev.com",
    "u.nu",
    "updating.me",
    "ur1.ca",
    "url4.eu",
    "urlao.com",
    "urlbrief.com",
    "url.co.uk",
    "urlcover.com",
    "urlcut.com",
    "urlenco.de",
    "urlhawk.com",
    "url.ie",
    "urlkiss.com",
    "urlot.com",
    "urlpire.com",
    "urlx.ie",
    "urlx.org",
    "urlzen.com",
    "use.my",
    "u.to",
    "v.gd",
    "virl.com",
    "vl.am",
    "vurl.com",
    "vzturl.com",
    "w3t.org",
    "wapo.st",
    "wapurl.co.uk",
    "wipi.es",
    "wp.me",
    "xaddr.com",
    "x.co",
    "xeeurl.com",
    "xr.com",
    "xrl.in",
    "xrl.us",
    "x.se",
    "xurl.es",
    "xurl.jp",
    "xzb.cc",
    "ye.pe",
    "yep.it",
    "yfrog.com",
    "yhoo.it",
    "ymlp.com",
    "yuarel.com",
    "yweb.com",
    "zi.ma",
    "zi.pe",
    "zipmyurl.com",
    "zurl.to",
    "zurl.ws",
    "zz.gd",
]


class URL:
    def __init__(self, url: str) -> None:
        if isinstance(url, bytes):
            url = url.decode()

        self.url = url
        self.domain = self.get_domain()
        self.top_level = self.get_top_level()
        self.is_shortened = False

    def get_domain(self) -> str:
        """Get the domain from a URL.

        :returns: Domain name extracted from URL
        :rtype: str

        """
        tld_obj = get_tld(self.url, as_object=True, fix_protocol=True)
        if isinstance(tld_obj, str):
            return tld_obj
        if tld_obj is None:
            return ""
        return tld_obj.parsed_url.netloc.lower().lstrip("www.")

    def get_top_level(self) -> str:
        """Get only the top-level domain from a URL.

        :returns: Top-level domain name extracted from URL
        :rtype: str

        """
        tld_obj = get_tld(self.url, as_object=True, fix_protocol=True)
        if isinstance(tld_obj, str):
            return tld_obj
        if tld_obj is None:
            return ""
        return tld_obj.fld.lower()

    def check_if_shortened(self) -> bool:
        """Check if the URL is among list of shortener services.


        :returns: True if the URL is shortened, otherwise False

        :rtype: bool

        """
        parsed_url = urlparse(self.url if "://" in self.url else f"//{self.url}")
        if self.domain.lower() == "goo.gl" and parsed_url.path.startswith("/maps/"):
            return False

        if self.domain.lower() in SHORTENER_DOMAINS:
            self.is_shortened = True

        return self.is_shortened

    def unshorten(self) -> Optional[str]:
        """Unshorten the URL by requesting an HTTP HEAD response."""

        if settings.NETWORK_ACCESS_ALLOWED is False:
            log.info(
                "Network access disabled (MVT_NETWORK_ACCESS_ALLOWED=False), "
                "skipping unshorten for %s",
                self.url,
            )
            return ""

        res = requests.head(self.url, timeout=settings.NETWORK_TIMEOUT)
        if str(res.status_code).startswith("30"):
            return res.headers["Location"]

        return ""
