import hashlib
import sys
from urllib.parse import urljoin

from django.conf import settings
from django.contrib.staticfiles.storage import staticfiles_storage


class RelativeAbsoluteUrl:
    """
    Represents a URL that can have both "relative" and "absolute" forms
    for various use either locally or remotely.
    """

    absolute: str
    relative: str

    def __init__(self, absolute: str, relative: str | None = None):
        if "://" not in absolute:
            raise ValueError(f"Absolute URL {absolute!r} is not absolute!")
        self.absolute = absolute
        self.relative = relative or absolute


class AutoAbsoluteUrl(RelativeAbsoluteUrl):
    """
    Automatically makes the absolute variant by using either settings.SITE_DOMAIN
    or a passed identity's URI domain.
    """

    def __init__(
        self,
        relative: str,
        identity=None,
    ):
        self.relative = relative
        if identity:
            absolute_prefix = f"https://{identity.domain.uri_domain}/"
        else:
            absolute_prefix = f"https://{settings.SITE_DOMAIN}/"
        self.absolute = urljoin(absolute_prefix, self.relative)


class ProxyAbsoluteUrl(AutoAbsoluteUrl):
    """
    AutoAbsoluteUrl variant for proxy paths, that also attaches a remote URI hash
    plus extension to the end if it can.
    """

    def __init__(
        self,
        relative: str,
        identity=None,
        remote_url: str | None = None,
    ):
        if remote_url:
            # See if there is a file extension we can grab
            extension = "bin"
            remote_filename = remote_url.split("/")[-1]
            if "." in remote_filename:
                extension = remote_filename.split(".")[-1]
            # When provided, attach a hash of the remote URL
            # SHA1 chosen as it generally has the best performance in modern python, and security is not a concern
            # Hash truncation is generally fine, as in the typical use case the hash is scoped to the identity PK.
            relative += f"{hashlib.sha1(remote_url.encode('ascii')).hexdigest()[:10]}.{extension}"
        super().__init__(relative, identity)


class StaticAbsoluteUrl(RelativeAbsoluteUrl):
    """
    Creates static URLs given only the static-relative path
    """

    def __init__(self, path: str):
        try:
            static_url = staticfiles_storage.url(path)
        except ValueError:
            # Suppress static issues during the first collectstatic
            # Yes, I know it's a big hack! Pull requests welcome :)
            if "collectstatic" in sys.argv:
                super().__init__("https://example.com/")
                return
            raise
        if "://" in static_url:
            super().__init__(static_url)
        else:
            super().__init__(
                urljoin(f"https://{settings.SITE_DOMAIN}/", static_url), static_url
            )
