import base64
import hashlib
import hmac
from datetime import datetime, timedelta
from urllib.parse import urlencode, urljoin


class UCloudClient:
    def __init__(self, public_key: str, private_key: str, bucket_name: str, base_url: str, tz_buffer: timedelta = timedelta(hours=7)):
        self.public_key = public_key
        self.private_key = private_key
        self.bucket_name = bucket_name
        self.base_url = base_url.rstrip("/")
        self.tz_buffer = tz_buffer

    def _signature(self, data: str) -> str:
        mac = hmac.new(self.private_key.encode(), data.encode(), hashlib.sha1)
        return base64.b64encode(mac.digest()).decode()

    def _sign_data(self, method: str, key: str, extra: str, content_md5="", content_type="", policy="") -> str:
        method = method.upper()
        resource = f"/{self.bucket_name}/{key}"
        sig_data = f"{method}\n{content_md5}\n{content_type}\n{extra}\n{resource}{policy}"
        return self._signature(sig_data)

    def get_presigned_get_url(self, key: str, expires_duration: timedelta) -> str:
        expires = str(int((datetime.utcnow() + expires_duration + self.tz_buffer).timestamp()))
        signature = self._sign_data("GET", key, expires)
        query = {
            "UCloudPublicKey": self.public_key,
            "Signature": signature,
            "Expires": expires
        }
        file_url = urljoin(self.base_url + "/", key)
        return f"{file_url}?{urlencode(query)}"

    def get_presigned_put_url(self, key: str, expires_duration: timedelta,
                              content_type: str = "", content_md5: str = "") -> str:
        expires = str(int((datetime.utcnow() + expires_duration + self.tz_buffer).timestamp()))
        signature = self._sign_data("PUT", key, expires, content_md5, content_type)
        query = {
            "UCloudPublicKey": self.public_key,
            "Signature": signature,
            "Expires": expires
        }
        file_url = urljoin(self.base_url + "/", key)
        return f"{file_url}?{urlencode(query)}"
