from base64 import b64encode
from urllib.parse import quote, urlsplit, urlunsplit

from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric.padding import PKCS1v15
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey
from cryptography.hazmat.primitives.hashes import SHA256
from cryptography.hazmat.primitives.serialization import load_pem_private_key


class ActionUrlSigner:
    __slots__ = ("_client_id", "_private_key")

    _client_id: int
    _private_key: RSAPrivateKey

    def __init__(self, client_id: int, key_file_name: str):
        self._client_id = client_id

        key_file = open(key_file_name, "rb")
        key_data = key_file.read()
        key_file.close()

        self._private_key = load_pem_private_key(
            key_data, password=None, backend=default_backend()
        )

    def _extend_query(self, query: str, name: str, value: str):
        pair = "{}={}".format(name, quote(value, safe=""))
        return f"{query}&{pair}" if query else pair

    def sign_url(self, url: str):
        url_parts = list(urlsplit(url))

        url_parts[3] = self._extend_query(url_parts[3], "client", str(self._client_id))
        url = urlunsplit(url_parts)

        signature = b64encode(
            self._private_key.sign(url.encode("ascii"), PKCS1v15(), SHA256())
        )
        url_parts[3] = self._extend_query(url_parts[3], "signature", signature)
        url = urlunsplit(url_parts)

        return url
