import hmac
from hashlib import sha1
import ctypes
import base64
import struct

# service type
MEDIA_CHANNEL_SERVICE = 1
RECORDING_SERVICE = 2
PUBLIC_SHARING_SERVICE = 3
IN_CHANNEL_PERMISSION = 4

# extra key
ALLOW_UPLOAD_IN_CHANNEL = 1

# permision
NoUpload = "0"
AudioVideoUpload= "3"

def generatePublicSharingKey(
        appID,
        appCertificate,
        channelName,
        unixTs,
        randomInt,
        uid,
        expiredTs
        ):
    return generateDynamicKey(
        PUBLIC_SHARING_SERVICE,
        appID,
        appCertificate,
        channelName,
        unixTs,
        randomInt,
        uid,
        expiredTs,{}
        )


def generateRecordingKey(
        appID,
        appCertificate,
        channelName,
        unixTs,
        randomInt,
        uid,
        expiredTs):
    return generateDynamicKey(
        RECORDING_SERVICE,
        appID,
        appCertificate,
        channelName,
        unixTs,
        randomInt,
        uid,
        expiredTs,
        {})


def generateMediaChannelKey(
        appID,
        appCertificate,
        channelName,
        unixTs,
        randomInt,
        uid,
        expiredTs):
    return generateDynamicKey(
        MEDIA_CHANNEL_SERVICE,
        appID,
        appCertificate,
        channelName,
        unixTs,
        randomInt,
        uid,
        expiredTs,
        {})


def generateInChannelPermissionKey(
        appID,
        appCertificate,
        channelName,
        unixTs,
        randomInt,
        uid,
        expiredTs,permission ):
    extra={}
    extra[ALLOW_UPLOAD_IN_CHANNEL]=permission
    return generateDynamicKey(
        IN_CHANNEL_PERMISSION,
        appID,
        appCertificate,
        channelName,
        unixTs,
        randomInt,
        uid,
        expiredTs,
        extra)


def generateDynamicKey(
        servicetype,
        appID,
        appCertificate,
        channelName,
        unixTs,
        randomInt,
        uid,
        expiredTs,
        extra
):
    uid = ctypes.c_uint(uid).value
    randomInt = ctypes.c_uint(randomInt).value
    signature = generateSignature(
        servicetype,
        appID,
        appCertificate,
        channelName,
        unixTs,
        randomInt,
        uid,
        expiredTs,
        extra
    )
    version = '{0:0>3}'.format(5)
    content = packUint16(servicetype) \
        + packString(signature)\
        + packString(appID.decode('hex'))\
        + packUint32(unixTs) \
        + packUint32(randomInt) \
        + packUint32(expiredTs)\
        + packMap(extra)
    return version + base64.b64encode(content)

def packUint16(x):
    return struct.pack('<H',int(x))

def packUint32(x):
    return struct.pack('<I',int(x))

def packInt32(x):
    return struct.pack('<i', int(x))

def packString(string):
    return packUint16(len(string)) + string

def packMap(m):
    ret = packUint16(len(m.items()))
    for k, v in m.items():
        ret += packUint16(k) + packString(v)
    return ret

def generateSignature(
        servicetype,
        appID,
        appCertificate,
        channelName,
        unixTs,
        randomInt,
        uid,
        expiredTs,
        extra,
):
    content = packUint16(servicetype) \
        + packString(appID.decode('hex'))\
        + packUint32(unixTs)  \
        + packUint32(randomInt)  \
        + packString(channelName) \
        + packUint32(uid)\
        + packUint32(expiredTs)\
        +  packMap(extra)
    signature = hmac.new(appCertificate.decode('hex'), content, sha1).hexdigest()
    return signature.upper()
