import sys, os, glob, urllib.parse
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))

from curl_cffi import requests
import json
from helpers.signature_generator import get_signature
from datetime import datetime
from pyplayready import Cdm, Device, PSSH


# From o11.py
def parse_params(params, name, default=""):
    ret = default
    for p in params:
        if p.split("=")[0] == name and len(p.split("=")) >= 2:
            ret = p[len(p.split("=")[0])+1:]
    return ret

action=parse_params(sys.argv, 'action')
proxy=parse_params(sys.argv, 'proxy')
serviceKey = parse_params(sys.argv, "serviceKey")
category = parse_params(sys.argv, "category").upper()
scriptPSSH=parse_params(sys.argv, 'pssh')
cdn=parse_params(sys.argv, "cdn")
COUNTRY=parse_params(sys.argv, 'country').upper()
user=parse_params(sys.argv, 'user')
password=parse_params(sys.argv, 'password')


PLATFORM = "LG"
DEVICE = "TV"
MODEL = "83G4WUA"
USER_AGENT = "Mozilla/5.0 (Web0S; Linux/SmartTV) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.128 Safari/537.36 WebAppManager"
PATH = os.getcwd() + f"/nowtv{COUNTRY}/"


proxies = {
    "http": proxy,
    "https": proxy
}

os.makedirs(PATH, exist_ok=True)

def login(email:str, password:str):
    session = requests.Session(proxies=proxies, impersonate="chrome_android")

    url = "https://rango.id.nowtv.com/signin/service/international"

    headers = {
        'accept': '*/*',
        'connection': 'keep-alive',
        'content-type': 'application/x-www-form-urlencoded',
        'host': 'rango.id.nowtv.com',
        'origin': 'https://tv.clients.nowtv.com',
        'referer': 'https://tv.clients.nowtv.com/',
        'user-agent': USER_AGENT,
        'x-skyott-activeterritory': COUNTRY,
        'x-skyott-device': DEVICE,
        'x-skyott-platform': PLATFORM,
        'x-skyott-proposition': 'NOWOTT',
        'x-skyott-provider': 'NOWTV',
        'x-skyott-territory': COUNTRY,
    }

    params = {
        'continuationUrl': 'https%3A%2F%2Frango.id.nowtv.com%2Foauth%2Fauthorize%2Fservice%2Finternational%3Fresponse_type%3Dtoken%26client_id%3Dnowtv_tvclient%26redirect_uri%3Dnowtv%3A%2F%2Fauth%26api_id%3Doauth',
    }

    payload = {
        "password": password,
        "rememberMe": "true",
        "userIdentifier": email
    }

    loginResponse = session.post(url, headers=headers, params=params, data=payload)

    if not loginResponse.ok:
        print(loginResponse.text)
        print("Error while login!")
        exit(1)

    href = loginResponse.json()['properties']['href']

    response = session.get(href, headers=headers)

    if not response.ok:
        print(response.text)
        print("Error while getting oauth!")
        exit(1)

    return response.json()['properties']['access_token']


def getToken(oauth):

    url = "https://ovp.nowtv.com/auth/tokens"

    headers = {
        'accept': 'application/vnd.tokens.v1+json',
        'connection': 'Keep-Alive',
        'content-type': 'application/vnd.tokens.v1+json',
        'host': 'ovp.nowtv.com',
        'user-agent': USER_AGENT,
        'x-sky-signature': 'SkyOTT client="NOWOTT-ANDROID-v1",signature="=",timestamp="",version="1.0"',
        'x-skyott-activeterritory': COUNTRY,
        'x-skyott-device': DEVICE,
        'x-skyott-platform': PLATFORM,
        'x-skyott-proposition': 'NOWOTT',
        'x-skyott-provider': 'NOWTV',
        'x-skyott-territory': COUNTRY,
    }

    payload = {
        "auth": {
            "authScheme": "OAUTH",
            "authToken": oauth,
            "provider": "NOWTV",
            "providerTerritory": COUNTRY,
            "proposition": "NOWOTT"
        },
        "device": {
            "type": DEVICE,
            "platform": PLATFORM,
            "id": "U0VDUEhPTkVfMDAwMDAwMDAwMDAwMDAwMDA3MjQwMjI",
            "drmDeviceId": "UNKNOWN"
        }
    }

    payload = json.dumps(payload)

    signature, timestamp = get_signature("POST", url, headers, payload)

    headers['x-sky-signature'] = f'SkyOTT client="NOWOTT-ANDROID-v1",signature="{signature}",timestamp="{timestamp}",version="1.0"'

    response = requests.post(url, data=payload, headers=headers, proxies=proxies, impersonate="chrome")

    if not response.ok:
        print(response.text)
        exit(1)

    else:
        return response.json()['userToken']

def getChannels(bouquet):

    url = "https://mobile.clients.nowtv.com/bff/channel_guide"

    languages = {
        "IT": "it-IT",
        "GB": "en-GB",
        "DE": "de-DE"
    }

    headers = {
        'connection': 'Keep-Alive',
        'host': 'mobile.clients.nowtv.com',
        'user-agent': 'NowottAndroid',
        'x-skyott-activeterritory': COUNTRY,
        'x-skyott-device': "MOBILE",
        'x-skyott-endorsements': 'epgAssetTile',
        'x-skyott-platform': "ANDROID",
        "x-skyott-language": languages[COUNTRY],
        'x-skyott-proposition': 'NOWOTT',
        'x-skyott-provider': 'NOWTV',
        'x-skyott-territory': COUNTRY,
    }


    date = datetime.today().strftime('%Y-%m-%d') + "T00:00+00:00"

    params = {
        
        'startTime': date,
        'discovery_content_segments': 'ENTERTAINMENT,HAYU,KIDS,MOVIES,NEWS,SHORTFORM,SPORTS,SPORTS_CORE,SPORTS_ESSENTIALS,SPORTS_EVENTS,SPORTS_EVENTS_EXCLUSIVE,SSN',
        'playout_content_segments': 'NEWS,SHORTFORM,SPORTS,SPORTS_BONUS,SPORTS_CORE,SPORTS_ESSENTIALS,SPORTS_EVENTS,SPORTS_EVENTS_EXCLUSIVE,SSN,SUPERSPORT,pkgcinema,pkgentertainment,pkgkids,pkgsport',
        'account_segments': 'DLOAD_USER,DOLBY,HD,NO_ADS,UHD',
    }

    response = requests.get(url, headers=headers, params=params, proxies=proxies, impersonate="chrome")

    if not response.ok:
        print(response.text)
        exit(1)

    channels = []

    for channel in response.json()['channels']:
        if channel['sectionNavigation'] == bouquet and channel['tileType'] == "linearChannel":
            channels.append({
                "name": channel['name'],
                "serviceKey": channel['serviceKey'],
            })

    return channels

def getPlayouts(serviceKey, token):
    
    url = "https://ovp.nowtv.com/video/playouts/live"

    headers = {
        'accept': 'application/vnd.playlive.v1+json',
        'connection': 'Keep-Alive',
        'content-type': 'application/vnd.playlive.v1+json',
        'host': 'ovp.nowtv.com',
        'user-agent': USER_AGENT,
        'x-sky-signature': '',
        'x-skyott-activeterritory': COUNTRY,
        'x-skyott-device': DEVICE,
        'x-skyott-platform': PLATFORM,
        'x-skyott-proposition': 'NOWOTT',
        'x-skyott-provider': 'NOWTV',
        'x-skyott-territory': COUNTRY,
        'x-skyott-usertoken': token,
    }

    payload = {
        "serviceKey": serviceKey,
        "device": {
            "capabilities": [
            {     
                "transport": "DASH",
                "protection": "NONE",
                "vcodec": "H265",
                "acodec": "AAC",
                "container": "ISOBMFF"
            },
            {
                "transport": "DASH",
                "protection": "PLAYREADY",
                "vcodec": "H265",
                "acodec": "AAC",
                "container": "ISOBMFF"
            },
            {
                "transport": "DASH",
                "protection": "NONE",
                "vcodec": "H264",
                "acodec": "AAC",
                "container": "ISOBMFF"
            },
            {
                "transport": "DASH",
                "protection": "PLAYREADY",
                "vcodec": "H264",
                "acodec": "AAC",
                "container": "ISOBMFF"
            }
            ],
            "model": MODEL,
            "maxVideoFormat": "HD",
            "hdcpEnabled": False,
            'supportedColourSpaces': [
                'DV',
                'HDR10',
                'SDR'
            ],
        },
        "client": {
            "thirdParties": [
            "COMSCORE",
            "CONVIVA",
            "FREEWHEEL",
            "FRV4"
            ],
            "timeShiftEnabled": False,
            "variantCapable": True
        },
        "personaParentalControlRating": 31
    }

    payload = json.dumps(payload)

    signature, timestamp = get_signature("POST", url, headers=headers, payload=payload)

    headers['x-sky-signature'] = f'SkyOTT client="NOWOTT-ANDROID-v1",signature="{signature}",timestamp="{timestamp}",version="1.0"'

    response = requests.post(url, data=payload, headers=headers, proxies=proxies, impersonate="chrome")

    if not response.ok:
        print(response.text)
        print("Can't get playouts!")
        exit()

    return {
        "mpd": response.json()['asset']['endpoints'][0]['url'].replace("_$dvrWindowDuration$", "_2hr"),
        "licenseToken":  response.json()['protection']['licenceToken']
    }

def getKeys(licenseToken, pssh, prd):

    url = "https://ovp.nowtv.com/drm/playready/acquirelicense"

    params = {
        "bt": licenseToken
    }

    headers = {
        'accept': '*/*',
        'accept-language': 'en-US,en;q=0.9,da;q=0.8',
        'content-type': 'text/xml; charset=UTF-8',
        'soapaction': '"http://schemas.microsoft.com/DRM/2007/03/protocols/AcquireLicense"',
        'user-agent': 'Mozilla/5.0 (Web0S; Linux/SmartTV) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.128 Safari/537.36 WebAppManager',
    }

    keys = []

    pssh = PSSH(pssh)

    device = Device.load(prd)

    cdm = Cdm.from_device(device)

    session = cdm.open()

    challenge = cdm.get_license_challenge(session, pssh.wrm_headers[0])

    response = requests.post(url, data=challenge, headers=headers, params=params, proxies=proxies)

    if not response.ok:
        print(response.status_code)
        print(response.text)
        print("Error while license!")
        exit(1)

    cdm.parse_license(session, response.text)

    for key in cdm.get_keys(session):
        if not f"{key.key_id.hex}:{key.key.hex()}" in keys:
            keys.append(f"{key.key_id.hex}:{key.key.hex()}")
    return keys

def getPRD():

    files = glob.glob(f"{PATH}/../*.prd")


    if len(files) == 0:
        print("\nNo .PRD found!")
        exit(1)
    else:
        prd = files[0]
    return prd

def loadOAUTH(email:str):
    try: 
        with open(PATH + f"/oauth_{email}.txt", "r") as f:
            return f.read().strip()
    except FileNotFoundError:
        return None
    
def storeOAUTH(email:str, oauth:str):
    with open(PATH + f"/oauth_{email}.txt", "w") as f:
        f.write(oauth)
    return

    
def removeToken(tokenizedUrl:str, cdn:str=None)->str:

    """Removes token and replaces cdn in url"""

    urlparsed = urllib.parse.urlparse(tokenizedUrl)

    cleanPath = urlparsed.path.split("/", 2)[2]

    return f"{urlparsed.scheme}://{cdn or urlparsed.netloc}/{cleanPath}{('?' + urlparsed.query if urlparsed.query else '')}"

def main():

    if not user or not password:
        print("Missing email or password!")
        exit(1)

    oauth = loadOAUTH(user)

    if not oauth:
        oauth = login(user, password)
        storeOAUTH(user, oauth)
    token = getToken(oauth)

    if action == "login":
        print("logged in successfully", file=sys.stderr)

    if action == "channels":
        items = getChannels(category)
        channels = []
        for item in items:
            channels.append({
                "Name": item['name'],
                "SessionManifest": True,
                "ManifestScript": f"serviceKey={item['serviceKey']}",
                "Autostart": False,
                "CdmType": "playready",
                "CdmMode": "external",
                "Cdm": f"serviceKey={item['serviceKey']}",
                "UseCdm": True,
                "Video": "best",
            })

        
        print(json.dumps(
                {
                    "Channels": channels
                },
                indent=2
            ))
        exit(0)
    
    if action == "manifest":
        token = getToken(oauth)
        playouts = getPlayouts(serviceKey, token)

        if cdn and "/v~" in playouts['mpd']:
            mpd = removeToken(playouts['mpd'], cdn)
        else:
            mpd = playouts['mpd']

        print(json.dumps(
            {
                "ManifestUrl": mpd
            }
        , indent=2))
        exit(0)

    if action == "cdm":
        prd = getPRD()
        token = getToken(oauth)
        playouts = getPlayouts(serviceKey, token)
        keys = getKeys(playouts['licenseToken'], scriptPSSH, prd)
        for key in keys:
            print(key)
        exit(0)


if __name__ == "__main__":
    main()
