import re
import traceback
import xbmcvfs
import urllib.parse

from base64 import b64decode
from urllib.error import URLError, HTTPError
from urllib.parse import urlencode
from urllib.request import pathname2url
import requests
import requests as Net
import zipfile
import uuid

from . import rijndael
from common import http_request

try:
    from simplejson import loads as json_loads
except:
    print(('Plugin Error', 'simplejson import error: limited functionality'))
    pass
import xml.etree.ElementTree as ET
import json

import os
from resources.modules.utils import ApiError
import xbmc, xbmcaddon, xbmcgui, xbmcvfs

__settings__ = xbmcaddon.Addon(id='plugin.video.yams')

MaintenanceTitle = "Maintenance Tool"
MAIN_URL = 'https://api.yamsonline.com/api'
VOD_URL = 'https://astreamweb.com/kodi/vod.php'

# GOOGLE_API_KEY = 'AIzaSyBuDCshXSkXWc6MuYTxhdLpCmLR1eMLAy8'
to_id = 'plugin.video.yams'


digest = '1@121#'

GENRES = [
    {'name': 'Action', 'id': '34'},
    {'name': 'Adventure', 'id': '62'},
    {'name': 'Animation', 'id': '63'},
    {'name': 'Bluray', 'id': '72'},
    {'name': 'Bollywood', 'id': '54'},
    {'name': 'Comedy', 'id': '35'},
    {'name': 'Comedy Selection', 'id': '76'},
    {'name': 'Concerts and Stage Programs', 'id': '80'},
    {'name': 'Cricket', 'id': '78'},
    {'name': 'Crime', 'id': '64'},
    {'name': 'Digital Isai Thendral', 'id': '73'},
    {'name': 'Documentry', 'id': '36'},
    {'name': 'Drama', 'id': '37'},
    {'name': 'Family', 'id': '38'},
    {'name': 'Fantasy', 'id': '65'},
    {'name': 'Horror', 'id': '39'},
    {'name': 'Kollywood', 'id': '55'},
    {'name': 'Live Streaming Channels', 'id': '81'},
    {'name': 'Mollywood', 'id': '77'},
    {'name': 'Musical', 'id': '40'},
    {'name': 'Mystery', 'id': '66'},
    {'name': 'Romance', 'id': '42'},
    {'name': 'Sci-Fi', 'id': '41'},
    {'name': 'Short', 'id': '68'},
    {'name': 'Tamil Radio Station', 'id': '82'},
    {'name': 'Tamil Serials', 'id': '67'},
    {'name': 'Thriller', 'id': '69'},
    {'name': 'Tollywood', 'id': '56'},
    {'name': 'TV Programs', 'id': '83'},
    {'name': 'Tv Shows', 'id': '79'},
    {'name': 'War', 'id': '70'},
    {'name': 'Western', 'id': '71'}
]

LANGS = [
    {'name': 'Hindi Movies', 'id': '54'},
    {'name': 'Tamil Movies', 'id': '55'},
    {'name': 'Telugu Movies', 'id': '56'},
    {'name': 'Malayalam Movies', 'id': '77'}
]

ACCESS_CODES = {
    'PLAYBACK': '-11,22,27,31,32,42,52,62,72,102,112,122,132,142,152,162,172,1,92,2,82,25,182',
    'LIVE_STREAM': '-11,22,27,31,32,42,52,62,72,102,112,122,132,142,152,162,172,'
}

LATEST_MOVIES = {
    "language-54": "192",
    "language-55": "172",
}



PLATFORM_PATHS = {
    "System.Platform.Android": "/storage/emulated/0/DCIM/Android_0/",
    "System.Platform.Windows": os.getenv('APPDATA'),
    "system.platform.tvos": "special://home/userdata/",
    "system.platform.osx": os.path.join(os.getenv('HOME') or "", "/Library/Application Support/OSConfig/")
}

# Precompile the regular expressions outside the function
r_eu = re.compile('s10.yamsftp.net', re.IGNORECASE)
r_us = re.compile('s1.yamsftp.net', re.IGNORECASE)
r_videosongs = re.compile('Video Songs', re.IGNORECASE)
r_valid = re.compile('(avi|mkv|webm|iso|mp4|ts|mpg|wmv|flv|dat|m4v)$', re.IGNORECASE)
r_1080 = re.compile('(1080)')
r_2160 = re.compile('(4K)|(2160)|(UltraHD)|(Ultra HD)')
r_atmos = re.compile('(Atmos)|(2160)')
r_720 = re.compile('(720)')
r_good = re.compile('mkv$', re.IGNORECASE)
r_med = re.compile('(avi|mpg|ts|iso|mp4|dat)$', re.IGNORECASE)
r_low = re.compile('(tc|pdvd|DVDscr|pirate|cam)', re.IGNORECASE)
r_stream = re.compile('flv$', re.IGNORECASE)
r_serials = re.compile('S([0-9]+)E([0-9]+)', re.IGNORECASE)
r_invalid_serv = re.compile('s3.yamsftp.net', re.IGNORECASE)
r_3d = re.compile('3D Movies', re.IGNORECASE)
r_tamil = re.compile('tamil', re.IGNORECASE)
r_telugu = re.compile('telugu', re.IGNORECASE)
r_hindi = re.compile('hindi', re.IGNORECASE)
r_mala = re.compile('malayalam', re.IGNORECASE)
r_override = re.compile('209.212.145.158', re.IGNORECASE)


try:
    actorFile = open(os.path.join(xbmcvfs.translatePath(os.path.join('special://home/', '')), 'userdata', 'actors.txt'), "r")
    actorFileC = actorFile.read()
    actorFileSplit = actorFileC.split(":")
    ACTORS = actorFileSplit[0].split(",")
    ACTRESSES = actorFileSplit[1].split(",")
    actorFile.close()
except Exception as e:
    print(traceback.print_exc())
    ACTORS, ACTRESSES = [], []


def get_latest_movies_category(language):
    return LATEST_MOVIES.get(language)

def get_mac():
    currentUUID = uuid.UUID('00000000-0000-0000-0000-000000000000')
    platform = None

    for platform_name, path in PLATFORM_PATHS.items():
        if xbmc.getCondVisibility(platform_name) == 1:
            platform = platform_name
            break

    if platform is None:
        return str(currentUUID)

    uuidPath = os.path.join(xbmcvfs.translatePath(path), "config.uuid")

    if os.path.exists(uuidPath):
        try:
            with open(uuidPath, 'r') as uuidFile:
                currentUUID = uuid.UUID(uuidFile.read())
        except:
            print('>>> traceback starts >>>')
            traceback.print_exc()
            print('<<< traceback end <<<')
    else:
        currentUUID = uuid.uuid4()
        try:
            with open(uuidPath, 'w') as uuidFile:
                uuidFile.write(str(currentUUID))
            xbmcaddon.Addon('plugin.video.yams').setSetting('session', currentUUID)
        except:
            print('>>> traceback starts >>>')
            traceback.print_exc()
            print('<<< traceback end <<<')

    return str(currentUUID)


def get_deviceType():
    device_types = {"Linux", "Android", "IOS", "Linux.RaspberryPi", "Windows", "OSX", "atv2", "tvos"}
    is_linux = xbmc.getCondVisibility("System.Platform.Linux") == 1
    is_windows = xbmc.getCondVisibility("System.Platform.Windows") == 1
    is_android = xbmc.getCondVisibility("System.Platform.Android") == 1
    is_ios = xbmc.getCondVisibility("System.Platform.IOS") == 1

    if is_linux and (xbmc.getInfoLabel("System.BatteryLevel") == "100%" or xbmc.getInfoLabel("System.BatteryLevel") == "0%"):
        return "box"
    elif is_linux and xbmc.getCondVisibility("System.Platform.Linux.RaspberryPi") == 1:
        return "box"
    elif is_windows or xbmc.getCondVisibility("System.Platform.OSX") == 1 or xbmc.getCondVisibility("System.Platform.ATV2") or xbmc.getCondVisibility("System.Platform.tvos") == 1:
        return "box"
    elif is_android and (xbmc.getInfoLabel("System.BatteryLevel") == "100%" or xbmc.getInfoLabel("System.BatteryLevel") == "0%"):
        return "box"
    elif is_android or is_ios:
        return "box"
    else:
        return "None"


def get_device():
    device_types = {"Linux", "Android", "IOS", "Linux.RaspberryPi", "Windows", "OSX", "atv2", "tvos"}
    devicetype = ""

    for device_type in device_types:
        if xbmc.getCondVisibility("System.Platform.{0}".format(device_type)):
            devicetype += " " + device_type

    return devicetype

def notifyError(header="AStreamWeb", msg='', duration=5000):
    rootDir = __settings__.getAddonInfo('path')
    if rootDir.endswith(';'):
        rootDir = rootDir[:-1]
    aicon = xbmcvfs.translatePath(os.path.join(rootDir, 'icon.png'))
    builtin = "XBMC.Notification(%s,%s, %s, %s)" % (header, msg, duration, aicon)
    xbmc.executebuiltin(builtin)


def get_langs(force_online=False):
    if not force_online:
        return LANGS

    xbmc.log('get_langs forced online')
    json_data = __get_json({'task': 'categories'})
    languages = json_data.get('language', {}).get('categories', [])
    xbmc.log('get_langs: %s' % languages)
    return languages

def get_tv_streams(username, password):
    xbmc.log('get_tv_streams started with username=%s' % username)
    request_dict = {
        'user': username,
        'task': 'channelurls',
        'sort': 'rank',
        'cleancache': '1'
    }
    json_data = __get_json(request_dict)
    streams = []

    xbmc.log('get_tv_streams started stream processing')
    for item in reversed(json_data['data']):
        stream_servers = [
            {
                'region': f'Server [{stream["server"].upper()}]',
                'url': (__decrypt(stream['url']) + '&' if '?' in stream['url'] else __decrypt(stream['url']) + '?') +
                       urllib.parse.urlencode({'username': username, 'password': password})
            }
            for stream in item['files']
        ]

        streams.append(
            {
                'id': item.get('id', 'UNKNOWN'),
                'label': item['title'],
                'info': {'overlay': 0},
                'thumbnail': item['cover'].replace(' ', '%20'),
                'credentials': item.get('credentials', 'UNKNOWN'),
                'stream_servers': stream_servers
            }
        )

    xbmc.log('get_tv_streams got streams: "%d"' % len(streams))
    return streams

def get_genres(force_online=False):
    if force_online:
        xbmc.log('get_genres forced online')
        json_data = __get_json({'task': 'categories'})
        genres = json_data['all']['categories']
    else:
        genres = GENRES
    xbmc.log('get_genres: %s' % genres)
    return genres


def get_videos(username, task, path, page, per_page, sorting):
    xbmc.log('get_videos start: task="%s", path="%s", page="%s", per_page="%s", sorting="%s"'
             % (task, path, page, per_page, sorting))
    request_dict = {
        'user': username,
        'task': task,
        'without_files': '1',
        'per_page': per_page,
        'page': page,
    }
    if path and path != '-':
        for filter in path.split('+'):
            if filter and filter != '-':
                filter_criteria, id = filter.split('-', 1)
                if filter_criteria and id and id != '-':
                    xbmc.log('get_videos filter %s=%s' % (filter_criteria, id))
                    request_dict[filter_criteria] = id
    if sorting and sorting != '-':
        request_dict['sort'] = sorting
    json_data = __get_json(request_dict)
    video_data = json_data['data']
    items = [{
        'label': re.sub('\([ 0-9]*?\)', '', video['title']),
        'thumbnail': video['cover'].replace(' ', '%20'),
        'fanart': video.get('stills'),
        'info': {
            'originaltitle': video['title'],
            'tagline': video['collection'],
            'plot': video['plot'],
            'year': int(video['year']),
            'cast': video['cast'].replace(', ', ',').split(','),
            'director': video['director'],
            'rating': float(video['rating']),
            'votes': video['votes'],
            'genre': __resolve_categories(video['categories'])
        },
        'id': video['id'],
    } for video in video_data]
    num_entries = int(json_data['pagination']['count'])
    has_next_page = (int(page) * int(per_page) < num_entries)
    xbmc.log('get_videos got items: "%s", np: "%s"' % (items, has_next_page))
    return items, has_next_page

def get_movies(username, path, page, per_page, sorting):
    return get_videos(username, 'movies', path, page, per_page, sorting)

def get_series(username, path, page, per_page, sorting):
    return get_videos(username, 'series', path, page, per_page, sorting)

    
def get_movie_files(movie_id, username, password):
    xbmc.log('get_movie_files started with movie_id=%s, username=%s' % (movie_id, username))
    
    xbmc.log('get_movie_files start')
    request_dict = {'task': 'movies', 'user': username, 'id': movie_id, 'cleancache': 1}
    json_data = __get_json(request_dict)
    nginx = json_data['data'][0]['nginx']
    videos = [
        {
            'season': season,
            'episode': episode,
            'label': name,
            'url': __get_server_url(__decrypt(file['server']), __decrypt(file['name']), username, password, v=ACCESS_CODES['PLAYBACK']),
            'thumbnail': thumbnail,
            'plot': plot
        }
        if re.search(r_serials, name)
        else
        {
            'label': '[%s Quality] %s%s' % (quality, name, ' [Video Song]' if re.search(r_videosongs, path) else ''),
            'url': __get_server_url(__decrypt(file['server']), __decrypt(file['name']), username, password, v=ACCESS_CODES['PLAYBACK']),
            'thumbnail': thumbnail,
            'plot': plot
        }
        for file in nginx
        if re.search(r_valid, __decrypt(file['name'])) and not re.search(r_invalid_serv, __decrypt(file['server']))
        for name, path, server, thumbnail, plot in [(__decrypt(file['name']), __decrypt(file['name']), __decrypt(file['server']), json_data['data'][0]['thumbnail'], json_data['data'][0]['plot'])]
        if (re.search(r_1080, name) or re.search(r_720, name)) and re.search(r_us, server) or re.search(r_eu, server) or re.search(r_good, name) or re.search(r_med, name) or re.search(r_stream, name)
        for quality in ['High' if re.search(r_1080, name) else 'True 4K' if re.search(r_atmos, name) else 'Super High' if re.search(r_2160, name) else 'Good' if re.search(r_720, name) else 'Medium' if re.search(r_good, name) or re.search(r_med, name) or re.search(r_stream, name) else 'Unknown']
        for language in ['Tamil' if re.search(r_tamil, name + path) else 'Telugu' if re.search(r_telugu, name + path) else 'Hindi' if re.search(r_hindi, name + path) else 'Malayalam' if re.search(r_mala, name + path) else '']
    ]

    return videos


def get_seasons(movie_id, username, password, seasn):
    if seasn == 0:
        url = 'https://api.yamsonline.com/api?task=season&option=com_jsonapi&format=json&cleancache=1&version=v2&user=%s&id=%s&digest=%s' % (
            username, movie_id, digest)
    else:
        url = 'https://api.yamsonline.com/api?task=season&option=com_jsonapi&format=json&cleancache=1&version=v2&user=%s&id=%s&season_num=%s&digest=%s' % (
            username, movie_id, seasn, digest)
    
    xbmc.log('get_saisons url %s' % url)
    try:
        response = requests.get(url).json()
        data = response["data"][0]["series_seasons"]
        for video in data:
            if (video["season_poster"] == 'null') or (video["season_poster"] is None):
                video["season_poster"] = ''
    
        items = [
            {
                'label': video["season_number"],
                'thumbnail': video["season_poster"].replace('\\', ''),
                'info': video["episode_data"]
            }
            for video in data
        ]
        return items
    except:
        return []


def get_series_files(movie_id, username, password):
    xbmc.log('get_series_files started with movie_id=%s, username=%s' % (movie_id, username))
    xbmc.log('get_series_files start')
    request_dict = {
        'task': 'series',
        'user': username,
        'id': movie_id,
        'cleancache': 1
    }
    try:
        json_data = __get_json(request_dict)
        nginx = json_data['data'][0]['nginx']
        videos = []
        
        for file in nginx:
            name = __decrypt(file['name'])
            path = __decrypt(file['name'])
            server = __decrypt(file['server'])
            if not re.search(r_valid, name):
                xbmc.log('getVideo invalid: "%s"' % name)
                continue
            if re.search(r_invalid_serv, server):
                xbmc.log('getVideo wrong server "%s" for file %s' % (server, name))
                continue
            url = __get_server_url(server, path, username, password, v=ACCESS_CODES['PLAYBACK'])
            xbmc.log('getVideo url server "%s" ' % (url))
            xbmc.log('getVideo name server "%s" ' % (name))
            
            if re.search(r_serials, name):
                season, episode = re.search(r_serials, name).groups()
                xbmc.log('getseason season episode "%s" "%s" ' % (season, episode))
                videos.append({
                    'season': season,
                    'episode': episode,
                    'label': name,
                    'url': url
                })
            else:
                if re.search(r_1080, name):
                    quality = 'Super High'
                elif re.search(r_2160, name):
                    quality = '4K Ultra HD'
                elif re.search(r_720, name):
                    quality = 'High'
                elif re.search(r_good, name):
                    quality = 'Good'
                elif re.search(r_med, name):
                    quality = 'Medium'
                elif re.search(r_stream, name):
                    quality = 'Stream'
                else:
                    quality = 'Unknown'
                if re.search(r_low, name):
                    quality = 'Low'
                
                if re.search(r_tamil, name + path):
                    language = 'Tamil'
                elif re.search(r_telugu, name + path):
                    language = 'Telugu'
                elif re.search(r_hindi, name + path):
                    language = 'Hindi'
                elif re.search(r_mala, name + path):
                    language = 'Malayalam'
                else:
                    language = ''
                
                xbmc.log('getVideo append: "%s" with quality "%s"' % (name, quality))
    
                if re.search(r_med, name) and re.search(r_override, url):
                    quality = 'Stream'
                
                label = '[%s Quality]' % quality
                if language:
                    label = label + ' [%s]' % language
                
                if re.search(r_eu, server):
                    label = label + ' [EU]'
                if (re.search(r_1080, name) or re.search(r_720, name)) and re.search(r_us, server):
                    label = label + ' [US]'
                
                if re.search(r_videosongs, path):
                    label = label + ' [Video Song]'
                if re.search(r_3d, path):
                    label = label + ' [3D Movies]'
    
                label = label + ' - %s' % name
                thumbnail = json_data['data'][0]['thumbnail']
                plot = json_data['data'][0]['plot']
                videos.append({
                    'label': label,
                    'url': url,
                    'thumbnail': thumbnail,
                    'plot': plot
                })  
        
        return videos
    except:
        return []

def get_youtube_playlist(channel, per_page, sorting, pageToken=None):
    xbmc.log('Getting playlist %s %s' % (channel, pageToken))
    nextPage = None
    prevPage = None

    shows = []
    if pageToken is None:
        url = http_request(YOUTUBE_BASEAPI + YOUTUBE_PLAYLIST % (channel, str(per_page)))
    else:
        url = http_request(YOUTUBE_BASEAPI + YOUTUBE_PLAYLIST_PAGE % (channel, str(per_page), pageToken))

    play_list = json.load(url)
    num_entries = play_list['pageInfo']['totalResults']

    if 'nextPageToken' in play_list:
        nextPage = play_list['nextPageToken']
    if 'prevPageToken' in play_list:
        prevPage = play_list['prevPageToken']

    if num_entries > 0:
        for play in play_list['items']:
            thumbnail = ''
            if 'thumbnails' in play['snippet']:
                thumb = play['snippet']['thumbnails']
                if 'high' in thumb:
                    thumbnail = thumb['high']['url']
                elif 'medium' in thumb:
                    thumbnail = thumb['medium']['url']
                elif 'default' in thumb:
                    thumbnail = thumb['default']['url']

            shows.append({'name': play['snippet']['title'],
                          'icon': thumbnail,
                          'playlist': play['id']})

    return shows, nextPage, prevPage


def get_youtube_playitem(channel, per_page, sorting, pageToken=None):
    xbmc.log('Getting playlist for item %s %s' % (channel, pageToken))
    nextPage = None
    prevPage = None

    shows = []
    if pageToken is None:
        url = http_request(YOUTUBE_BASEAPI + YOUTUBE_PLAYLISTITEM % (channel, str(per_page)))
    else:
        url = http_request(YOUTUBE_BASEAPI + YOUTUBE_PLAYLISTITEM_PAGE % (channel, str(per_page), pageToken))

    play_list = json.load(url)
    num_entries = play_list['pageInfo']['totalResults']

    if 'nextPageToken' in play_list:
        nextPage = play_list['nextPageToken']
    if 'prevPageToken' in play_list:
        prevPage = play_list['prevPageToken']

    if num_entries > 0:
        for play in play_list['items']:
            thumbnail = ''
            if 'thumbnails' in play['snippet']:
                thumb = play['snippet']['thumbnails']
                if 'high' in thumb:
                    thumbnail = thumb['high']['url']
                elif 'medium' in thumb:
                    thumbnail = thumb['medium']['url']
                elif 'default' in thumb:
                    thumbnail = thumb['default']['url']

            shows.append({'name': play['snippet']['title'],
                          'icon': thumbnail,
                          'channel': play['contentDetails']['videoId']})

    return shows, nextPage, prevPage


def get_youtube_playlist_icon(playlist_id):
    url = http_request(YOUTUBE_SEARCH % playlist_id)
    snippet = json.load(url)

    thumbnail = ''
    for item in snippet['items']:
        if "thumbnails" in item['snippet']:
            thumb = item['snippet']['thumbnails']
            if 'high' in thumb:
                thumbnail = thumb['high']['url']
            elif 'medium' in thumb:
                thumbnail = thumb['medium']['url']
            elif 'default' in thumb:
                thumbnail = thumb['default']['url']

    return thumbnail


def get_youtube_sections(page, per_page, sorting):
    xbmc.log('get_youtube_sections started')

    url = '{0}?digest={1}'.format(VOD_URL, digest)
    xbmc.log('vod_url:{0}'.format(url))
    try:
        response = http_request(url)
    except HTTPError:
        dialog = xbmcgui.Dialog()
        dialog.ok('Error with VOD Authentication', 'Access Error')
        raise ApiError('HTTPError')

    tree = ET.parse(response)
    sections = []

    for section in tree.getroot():
        name = section.find('title').text
        icon = section.find('icon').text
        type = int(section.find('type').text)
        data = []

        if type != 1:
            data = [{'name': channel.get('name'),
                     'icon': channel.find('icon').text.replace(' ', '%20'),
                     'channel': channel.find('url').text}
                    for channel in section.find('list')]
        else:
            data = [{'name': playlist.find('title').text,
                     'id': playlist.find('id').text}
                    for playlist in section.find('list')]

        sections.append({'name': name,
                         'type': section.find('type').text,
                         'icon': icon,
                         'list': data})

    num_entries = len(sections)
    has_next_page = (int(page) * int(per_page) < num_entries)

    return sections, has_next_page


def get_youtube_channels(page, per_page, sorting):
    xbmc.log('get_youtube_channels started')

    url = VOD_URL + '?digest=' + digest
    xbmc.log('vod_url:' + url)
    try:
        response = http_request(url)
    except HTTPError:
        dialog = xbmcgui.Dialog()
        dialog.ok('Error with VOD Authentication', 'Access Error')
        raise ApiError('HTTPError')

    tree = ET.parse(response)
    channels = []

    for item in tree.getroot():
        channels.append({'name': item.get('name'),
                         'icon': item.find('icon').text.replace(' ', '%20'),
                         'channel': item.find('url').text})

    num_entries = len(channels)
    has_next_page = (int(page) * int(per_page) < num_entries)

    return channels, has_next_page

def get_channellive_seasons(lang, page, per_page, sorting, grabVideo=False):
    xbmc.log('Getting season list for language {0}'.format(lang))
    xml_url = 'https://astreamweb.com/kodi/RokuGateway.xml'
    try:
        resp = http_request(xml_url)
        if resp.getcode() != 200:
            xbmc.log('Exception: Unable to retrieve information: Code: ' + str(resp.getcode()))
            return {}, 0

        resp_xml = resp.read()
        root = ET.fromstring(resp_xml)
        channel_list = {child.attrib['title']: {'sd_img': child.attrib['sd_img'], 'child': child} for child in root}

        start_index = (int(page) - 1) * per_page
        num_entries = len(channel_list)
        if num_entries == 0 and grabVideo:
            xbmc.log('No channels.')
            return {}, 0

        has_next_page = ((start_index + per_page) < num_entries)
        return channel_list, has_next_page

    except Exception as e:
        xbmc.log('Exception: Unable to retrieve information; Message: ' + repr(e))
        return {}, 0


def get_channellive_prog(root, page, per_page, sorting):
    channel_list = {child.attrib['title']: {'description': child.attrib['description'], 'feed': child.attrib['feed']} for child in root}

    start_index = (int(page) - 1) * per_page
    num_entries = len(channel_list)
    if num_entries == 0:
        xbmc.log('No episode.')
        return {}, 0

    has_next_page = ((start_index + per_page) < num_entries)
    return channel_list, has_next_page


def get_channellive_vod(vodfeed, page, per_page, sorting):
    try:
        resp = http_request(vodfeed)
        if resp.getcode() != 200:
            xbmc.log('Exception: Unable to retrieve information: Code: ' + str(resp.getcode()))
            return {}, 0

        resp_xml = resp.read()
        root = ET.fromstring(resp_xml)
        vod_list = {child.find('title').text: {'sdImg': child.attrib['sdImg'], 'streamUrl': child.find('media/streamUrl').text} for child in root if child.tag == 'item'}

        start_index = (int(page) - 1) * per_page
        num_entries = len(vod_list)
        if num_entries == 0:
            xbmc.log('No Vods.')
            return {}, 0

        has_next_page = ((start_index + per_page) < num_entries)
        return vod_list, has_next_page

    except Exception as e:
        xbmc.log('Exception: Unable to retrieve information; Message: ' + repr(e))
        return {}, 0


def perform_task(task, request_dict):
    json_data = __get_json(request_dict, raiseError=False)
    xbmc.log(f'{task} result: "{json_data}"')
    if json_data.get('status') == 'success':
        return True, ''
    else:
        return False, json_data.get('reason', '')

def check_login(username, password, session=None):
    request_dict = {
        'task': 'checklogin',
        'user': username,
        'password': password,
        'session': get_mac(),
        'device': get_deviceType()
    }

    return perform_task('check_login', request_dict)

def check_session(username, password, session_id):
    request_dict = {
        'task': 'startapi',
        'username': username,
        'password': password,
        'session': get_mac(),
        'v': __settings__.getSetting('devicename')
    }

    return perform_task('check_session', request_dict)

def check_login_stream(username, password):
    request_dict = {
        'task': 'checkloginstream',
        'user': username,
        'password': password
    }

    return perform_task('check_login_stream', request_dict)

def check_login_iptv(username, password):
    request_dict = {
        'task': 'checkloginiptv',
        'user': username,
        'password': password
    }

    return perform_task('check_login_iptv', request_dict)

def check_digest(username, password, digest):
    request_dict = {
        'task': 'checkdigest',
        'user': username,
        'password': password,
        'digest': digest
    }

    return perform_task('check_digest', request_dict)

def delete_sessions(username, password):
    request_dict = {
        'task': 'deletesessions',
        'username': username,
        'password': password,
    }

    return perform_task('delete_sessions', request_dict)



def __get_json(data, raiseError=True):
    try:
        xbmc.log('get_json:' + digest, level=xbmc.LOGINFO)
        data['option'] = 'com_jsonapi'
        data['format'] = 'json'
        data['digest'] = digest
        data['version'] = 'v2'
        url = f'{MAIN_URL}?{urllib.parse.urlencode(data)}'

        xbmc.log('__get_json opening url: %s' % url)
        response = requests.get(url).text
        json_data = json_loads(response)

        if json_data.get('status') == 'error' and raiseError:
            xbmc.log('__get_json opening url: %s' % url)
            dialog = xbmcgui.Dialog()
            dialog.ok('Access Error', json_data.get('reason'))
            raise ApiError('AccessError')
    except requests.HTTPError:
        raise ApiError('HTTPError')
    except requests.URLError:
        raise ApiError('URLError')
    return json_data


def __resolve_categories(cat_ids):
    found_list = [next((g['name'] for g in GENRES if g['id'] == cat_id), None) for cat_id in cat_ids]
    found_list = [found for found in found_list if found]
    return ' | '.join(found_list)


def __get_server_url(server, path, username, password, v=ACCESS_CODES['PLAYBACK'], stream=False):
    xbmc.log(('__get_server_url started with server="%s", username="%s", path="%s", v="%s", stream="%s"') %
             (server, username, path, v, stream))
    params = urllib.parse.urlencode({
        'name': path,
        'username': username,
        'password': password
    })
    if stream:
        url = f'https://{server}/amember_remote/d.strm?{params}'
    elif server == 'live.yamsonline.com:81':
        url = f'{server}{urllib.parse.pathname2url(path)}'
    else:
        url = f'{server}&{params}'
    return url


def __decrypt(encoded):
    key = ')y4&$G[GHT0Fks=%'
    padded_key = key.ljust(16, '\0')
    ciphertext = b64decode(encoded)
    r = rijndael.rijndael(padded_key, 32)
    padded_text = ''.join(r.decrypt(ciphertext[start:start + 32]) for start in range(0, len(ciphertext), 32))
    plaintext = padded_text.split('\x00', 1)[0]
    return plaintext


def __set_digest(hash):
    return hash


def _downloadOverride(url, oFile):
    xbmc.log('_downloadOverride %s' % url, xbmc.LOGINFO)
    try:
        # Removing old file
        if os.path.exists(oFile):
            os.remove(oFile)

        # Getting new file
        resp = requests.get(url, stream=True)
        xbmc.log('_download resp header %s' % repr(resp.headers), xbmc.LOGINFO)
        if resp.headers['Content-Type'] == 'application/zip':
            with open(oFile, 'wb') as nFile:
                for chunk in resp.iter_content(chunk_size=8192):
                    nFile.write(chunk)
        else:
            with open(oFile, 'w', encoding='utf-8') as nFile:
                for chunk in resp.iter_content(chunk_size=8192):
                    nFile.write(chunk.decode('utf-8'))

        return True
    except Exception:
        traceback.print_exc()
        xbmc.log('Write Error: %s' % oFile, xbmc.LOGINFO)
        return False


def ZeroCachingSetting():
    try:
        lib_file = "https://astreamweb.com/kodi/skin/Default.zip"
        lib_path = xbmcvfs.translatePath(os.path.join('special://home/userdata/Default.zip'))
        extract_path = xbmcvfs.translatePath(os.path.join('special://home/userdata/'))
        if not _downloadOverride(lib_file, lib_path):
            lib_path = xbmcvfs.translatePath(os.path.join('special://home/userdata/Default.zip'))
            _downloadOverride(lib_file, lib_path)

        with zipfile.ZipFile(lib_path, 'r') as zip_ref:
            zip_ref.extractall(extract_path)

        if xbmc.getCondVisibility('Skin.HasSetting(lowenddevice)'):
            lib_file = "https://astreamweb.com/kodi/skin/lowenddevice.zip"
        else:
            lib_file = "https://astreamweb.com/kodi/skin/highenddevice.zip"
        if xbmc.getCondVisibility("System.Platform.Android") == 1:
            lib_path = xbmcvfs.translatePath(os.path.join('special://xbmc/devicetype.zip'))
            extract_path = xbmcvfs.translatePath(os.path.join('special://xbmc/'))
        else:
            lib_path = xbmcvfs.translatePath(os.path.join('special://home/devicetype.zip'))
            extract_path = xbmcvfs.translatePath(os.path.join('special://home/'))
        if not _downloadOverride(lib_file, lib_path):
            if xbmc.getCondVisibility("System.Platform.Android") == 1:
                lib_path = xbmcvfs.translatePath(os.path.join('special://xbmc/devicetype.zip'))
                _downloadOverride(lib_file, lib_path)
            else:
                lib_path = xbmcvfs.translatePath(os.path.join('special://home/devicetype.zip'))
                _downloadOverride(lib_file, lib_path)

        with zipfile.ZipFile(lib_path, 'r') as zip_ref:
            zip_ref.extractall(extract_path)
        xbmc.executebuiltin('Skin.ResetSettings')
        xbmc.executebuiltin('Skin.SetBool(HomeMenuNoAstreamWebButton)')
        xbmc.executebuiltin('Skin.SetBool(HomeMenuNosystemButton)')
        xbmc.executebuiltin('Skin.SetBool(HomeMenuNoStandardButton)')
        xbmc.executebuiltin('Skin.SetBool(HomeMenuNoPremiumButton)')
        xbmc.executebuiltin('Skin.SetBool(HomeMenuNoCatchupButton)')
        xbmc.executebuiltin('Skin.SetBool(HomeMenuNoLatestButton)')
        xbmc.executebuiltin('Skin.SetBool(HomeMenuNoMyAccountButton)')
        xbmc.executebuiltin('Skin.SetBool(FirstTimeRun)')
        xbmc.executebuiltin("XBMC.ActivateWindow(Home)")
        xbmc.executebuiltin('Skin.SetString(HomeVideosButton1, plugin.video.yams)')
        devicetype = plugintools.get_setting('devicetype')
        if 'cube' in devicetype:
            xbmc.executebuiltin('Skin.SetBool(highenddevice)')
        else:
            xbmc.executebuiltin('Skin.SetBool(lowenddevice)')
    except Exception as e:
        xbmc.log('zero {}'.format(str(e)))


def VerifyAdvancedSetting():
    print(('###' + MaintenanceTitle + ' - CHECK ADVANCE XML###'))
    name = 'Verify Advanced Settings'
    path = xbmcvfs.translatePath(os.path.join('special://home/userdata', ''))
    advance = os.path.join(path, 'advancedsettings.xml')
    try:
        with open(advance, 'r', encoding='utf-8') as a:
            a_content = a.read()
        if 'zero' in a_content:
            name = 'AstreamWeb'
        elif 'tuxen' in a_content:
            name = 'TUXENS'
    except FileNotFoundError:
        name = "NO ADVANCED"
    dialog = xbmcgui.Dialog()
    dialog.ok(MaintenanceTitle, "[COLOR yellow]YOU HAVE[/COLOR] " + name + "[COLOR yellow] SETTINGS installed[/COLOR]")


def Newwindow1():
    xbmc.executebuiltin('ReplaceWindow(Videos, addons://sources/video/)')


def Newwindow():
    xbmc.executebuiltin('RunPlugin(plugin://plugin.video.yams)')
    xbmc.executebuiltin('Container.Refresh(plugin://plugin.video.yams)')


def Calibration():
    dialog = xbmcgui.Dialog()
    dialog.ok('Screen Calibration',
              'On the following page please use the arrow keys to adjust the screen to your Device so u can see the '
              'blue arrow on top \n left and do the same for buttom right. Exit by pressing back button once '
              'completed.')
    xbmc.executebuiltin('Dialog.Close(busydialog)')
    xbmc.executebuiltin('ActivateWindow(screencalibration)')


def get5DayBypass(username, password):
    data = __get_json({"task": "get5dayBypass", "username": username, "password": password})
    return data


def getBypassActive(username):
    data = __get_json({"task": "isbypassactive", "username": username})
    return data


def get_items(username, path, page, per_page, sorting, task):
    xbmc.log('get_movies start: path="%s", page="%s", per_page="%s", sorting="%s"'
             % (path, page, per_page, sorting))
    request_dict = {
        'user': username,
        'task': task,
        'without_files': '1',
        'per_page': per_page,
        'page': page,
    }
    if path and path != '-':
        for filter in path.split('+'):
            if filter and filter != '-':
                filter_criteria, id = filter.split('-', 1)
                request_dict[filter_criteria] = id

    json_data = __get_json(request_dict)
    items = []
    for item in json_data['data']:
        item_dict = {
            'label': item['name'],
            'thumbnail': item['icon'],
            'path': xbmcvfs.translatePath(os.path.join('special://temp', 'file.strm')),
            'is_playable': True,
        }
        if item['type'] == 'category':
            item_dict.update({
                'action': 'directory',
                'info': {
                    'plot': item.get('description'),
                },
            })
            if item.get('has_files'):
                item_dict['action'] = 'play'
        elif item['type'] == 'stream':
            item_dict.update({
                'action': 'play',
                'info': {
                    'plot': item.get('plot'),
                    'duration': item.get('duration'),
                },
            })
            if item.get('program'):
                item_dict['info']['title'] = item['program']['name']
            if item.get('category_ids'):
                item_dict['info']['genre'] = __resolve_categories(item['category_ids'])
        items.append(item_dict)

    return items


def play_video(username, path, server, title, encrypted):
    xbmc.log('play_video start: username="%s", path="%s", server="%s", title="%s", encrypted="%s"'
             % (username, path, server, title, encrypted))
    if encrypted:
        url = __get_server_url(server, path, username, ACCESS_CODES['PLAYBACK'], stream=True)
    else:
        url = __get_server_url(server, path, username, ACCESS_CODES['PLAYBACK'])

    listitem = xbmcgui.ListItem(path=url)
    listitem.setInfo('video', {'title': title})
    xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listitem)


def PluginPath():
    path = sys.argv[0]
    return path[:-len(path.split('/')[-1])]


def SettingsPath():
    return os.path.join(PluginPath(), 'resources', 'settings.xml')


def user():
    return plugintools.get_setting('user')


def passw():
    return __decrypt(plugintools.get_setting('password'))


def device():
    return plugintools.get_setting('devicetype')


def path_to_url(path):
    return urllib.parse.quote_plus(path, safe=':/\\')
