import base64, json, requests
from enum import Enum, IntEnum
from hashlib import sha1
from Cryptodome.Cipher import AES
from Cryptodome.Util import Padding

class TrackType(str, Enum):
    SD = "SD"
    HD = "HD"
    AUDIO = "AUDIO"


class WidevineError(IntEnum):
    DRM_DEVICE_CERTIFICATE_REVOKED = 127
    DRM_DEVICE_CERT_SERIAL_REVOKED = 175
    INVALID_PSSH = 152
    INVALID_LICENSE_CHALLENGE = 106


# -------------------------------------------------------------------
# Constants
# -------------------------------------------------------------------

AES_KEY = bytes.fromhex(
    "1ae8ccd0e7985cc0b6203a55855a1034afc252980e970ca90e5202689f947ab9"
)
AES_IV = bytes.fromhex(
    "d58ce954203b7c9a9a9d467f59839249"
)

PROVIDER = "widevine_test"
CONTENT_ID = "ZmtqM2xqYVNkZmFsa3Izag=="  # example content id

def build_request(challenge) -> dict:
    """Build signed Widevine license request payload."""
    if not isinstance(challenge, str):
        challenge = base64.b64encode(challenge).decode()

    payload = json.dumps(
        {
            "payload": challenge,
            "provider": PROVIDER,
            "content_id": CONTENT_ID,
            "content_key_specs": [{"track_type": t.value} for t in TrackType],
        },
        separators=(",", ":"),
    ).encode()

    request_b64 = base64.b64encode(payload).decode()

    # Widevine-style signature
    digest = sha1(base64.b64decode(request_b64)).digest()
    cipher = AES.new(AES_KEY, AES.MODE_CBC, AES_IV)
    signature = base64.b64encode(cipher.encrypt(Padding.pad(digest, 16))).decode()

    return {
        "request": request_b64,
        "signature": signature,
        "signer": PROVIDER,
    }


def check_response(resp: dict):
    """Check for error status and raise if needed."""
    code = resp.get("internal_status")
    if not code:
        return

    try:
        error = WidevineError(code)
        raise RuntimeError(f"License error: {error.name} ({code})")
    except ValueError:
        # Unknown code, ignore
        return

if __name__ == "__main__":
    pssh = "CAESEFoHzpkm/EolkmbSIjR2qgkaCHVzcC1jZW5jIhhXZ2ZPbVNiOFNpV1NadElpTkhhcUNRPT0qADIA"
    challenge = "CAQ="

    # 1. Request service certificate
    cert_resp = requests.post(
        "https://license.widevine.com/cenc/getlicense/widevine_test",
        json=build_request(challenge),
    ).json()
    service_cert = cert_resp.get("license")

    challenge = "" # use pywidevine to generate B64 challenge using pssh, service_cert

    # 2. Issue real license request
    license_resp = requests.post(
        "https://license.widevine.com/cenc/getlicense/widevine_test",
        json=build_request(challenge),
    ).json()

    check_response(license_resp)

    print("level:", license_resp.get("security_level"))
    print("systemID:", license_resp.get("system_id"))
    print("status:", license_resp.get("device_state"))
