# -*- coding: utf-8 -*-

#################################################################################################

import json
import logging
import os

import xbmc
import xbmcvfs

from objects.obj import Objects
from helper import _, api, window, settings, dialog, event, JSONRPC
from emby import Emby

#################################################################################################

LOG = logging.getLogger("EMBY."+__name__)

#################################################################################################


class Player(xbmc.Player):

    # Borg - multiple instances, shared state
    _shared_state = {}
    played = {}
    up_next = False

    def __init__(self):

        self.__dict__ = self._shared_state
        xbmc.Player.__init__(self)

    def onPlayBackStarted(self):

        ''' We may need to wait for info to be set in kodi monitor.
            Accounts for scenario where Kodi starts playback and exits immediately.
        '''
        self.up_next = False
        count = 0
        monitor = xbmc.Monitor()

        try:
            current_file = self.getPlayingFile()
        except Exception:

            while count < 5:
                try:
                    current_file = self.getPlayingFile()
                    count = 0
                    break
                except Exception:
                    count += 1

                if monitor.waitForAbort(1):
                    return
            else:
                LOG.info('Cancel playback report')

                return

        items = window('emby_play.json')
        item = None

        while not items:

            if monitor.waitForAbort(2):
                return

            items = window('emby_play.json')
            count += 1

            if count == 20:
                LOG.info("Could not find emby prop...")

                return

        for item in items:
            if item['Path'] == current_file.decode('utf-8'):
                items.pop(items.index(item))

                break
        else:
            item = items.pop(0)

        window('emby_play.json', items)

        self.set_item(current_file, item)
        data = {
            'QueueableMediaTypes': "Video,Audio",
            'CanSeek': True,
            'ItemId': item['Id'],
            'MediaSourceId': item['MediaSourceId'],
            'PlayMethod': item['PlayMethod'],
            'VolumeLevel': item['Volume'],
            'PositionTicks': int(item['CurrentPosition'] * 10000000),
            'IsPaused': item['Paused'],
            'IsMuted': item['Muted'],
            'PlaySessionId': item['PlaySessionId'],
            'AudioStreamIndex': item['AudioStreamIndex'],
            'SubtitleStreamIndex': item['SubtitleStreamIndex']
        }
        item['Server']['api'].session_playing(data)
        window('emby.skip.%s.bool' % item['Id'], True)

        if monitor.waitForAbort(2):
            return

        self.set_audio_subs(item['AudioStreamIndex'], item['SubtitleStreamIndex'])

    def set_item(self, file, item):

        ''' Set playback information.
        '''
        try:
            item['Runtime'] = int(item['Runtime'])
        except (TypeError, ValueError):
            try:
                item['Runtime'] = int(self.getTotalTime())
                LOG.info("Runtime is missing, Kodi runtime: %s" % item['Runtime'])
            except Exception:
                item['Runtime'] = 0
                LOG.info("Runtime is missing, Using Zero")

        try:
            seektime = self.getTime()
        except Exception: # at this point we should be playing and if not then bail out
            return

        result = JSONRPC('Application.GetProperties').execute({'properties': ["volume", "muted"]})
        result = result.get('result', {})
        volume = result.get('volume')
        muted = result.get('muted')

        item.update({
            'File': file,
            'CurrentPosition': item.get('CurrentPosition') or int(seektime),
            'Muted': muted,
            'Volume': volume,
            'Server': Emby(item['ServerId']),
            'Paused': False
        })

        self.played[file] = item
        LOG.info("-->[ play/%s ] %s", item['Id'], item)

    def set_audio_subs(self, audio=None, subtitle=None):

        ''' Only for after playback started
        '''
        LOG.info("Setting audio: %s subs: %s", audio, subtitle)
        current_file = self.getPlayingFile()

        if current_file in self.played:

            item = self.played[current_file]
            mapping = item['SubsMapping']

            if audio and len(self.getAvailableAudioStreams()) > 1:
                self.setAudioStream(audio - 1)

            if subtitle is None:
                return

            tracks = len(self.getAvailableAudioStreams())

            if subtitle == -1:
                self.showSubtitles(False)

            elif mapping:
                for index in mapping:

                    if mapping[index] == subtitle:
                        self.setSubtitleStream(int(index))

                        break
                else:
                    self.setSubtitleStream(len(mapping) + subtitle - tracks - 1)
            else:
                self.setSubtitleStream(subtitle - tracks - 1)

    def detect_audio_subs(self, item):

        params = {
            'playerid': 1,
            'properties': ["currentsubtitle","currentaudiostream","subtitleenabled"]
        }
        result = JSONRPC('Player.GetProperties').execute(params)
        result = result.get('result')

        try: # Audio tracks
            audio = result['currentaudiostream']['index']
        except (KeyError, TypeError):
            audio = 0
        
        try: # Subtitles tracks
            subs = result['currentsubtitle']['index']
        except (KeyError, TypeError):
            subs = 0

        try: # If subtitles are enabled
            subs_enabled = result['subtitleenabled']
        except (KeyError, TypeError):
            subs_enabled = False

        item['AudioStreamIndex'] = audio + 1

        if not subs_enabled or not len(self.getAvailableSubtitleStreams()):
            item['SubtitleStreamIndex'] = None

            return

        mapping = item['SubsMapping']
        tracks = len(self.getAvailableAudioStreams())

        if mapping:
            if str(subs) in mapping:
                item['SubtitleStreamIndex'] = mapping[str(subs)]
            else:
                item['SubtitleStreamIndex'] = subs - len(mapping) + tracks + 1
        else:
            item['SubtitleStreamIndex'] = subs + tracks + 1

    def next_up(self):

        current_file = self.getPlayingFile()
        item = self.played[current_file]
        objects = Objects()

        if item['Type'] != 'Episode':
            return

        next_items = item['Server']['api'].get_adjacent_episodes(item['CurrentEpisode']['tvshowid'], item['Id'])

        for index, next_item in enumerate(next_items['Items']):
            if next_item['Id'] == item['Id']:

                try:
                    next_item = next_items['Items'][index + 1]
                except IndexError:
                    LOG.warn("No next up episode.")

                    return

                break

        API = api.API(next_item, item['Server']['auth/server-address'])
        data = objects.map(next_item, "UpNext")
        artwork = API.get_all_artwork(objects.map(next_item, 'ArtworkParent'), True)
        data['art'] = {
            'tvshow.poster': artwork.get('Series.Primary'),
            'tvshow.fanart': None,
            'thumb': artwork.get('Primary')
        }
        if artwork['Backdrop']:
            data['art']['tvshow.fanart'] = artwork['Backdrop'][0]

        next_info = {
            'play_info': {'ItemIds': [data['episodeid']], 'ServerId': item['ServerId'], 'PlayCommand': 'PlayNow'},
            'current_episode': item['CurrentEpisode'],
            'next_episode': data
        }

        LOG.debug("--[ next up ] %s", json.dumps(next_info, indent=4))
        event("upnext_data", next_info, hexlify=True)

    def onPlayBackPaused(self):
        current_file = self.getPlayingFile()

        if current_file in self.played:

            self.played[current_file]['Paused'] = True
            self.report_playback()
            LOG.debug("-->[ paused ]")

    def onPlayBackResumed(self):
        current_file = self.getPlayingFile()

        if current_file in self.played:

            self.played[current_file]['Paused'] = False
            self.report_playback()
            LOG.debug("--<[ paused ]")

    def onPlayBackSeek(self, time, seekOffset):

        ''' Does not seem to work in Leia??
        '''
        try:
            current_file = self.getPlayingFile()
        except Exception:
            return

        if current_file in self.played:

            self.report_playback()
            LOG.info("--[ seek ]")

    def report_playback(self, report=True):

        ''' Report playback progress to emby server.
            Check if the user seek.
        '''
        try:
            current_file = self.getPlayingFile()

            if current_file not in self.played:
                return
        except Exception as error:
            LOG.error(error)

            return

        item = self.played[current_file]

        if window('emby.external.bool'):
            return

        if not report:

            previous = item['CurrentPosition']
            item['CurrentPosition'] = int(self.getTime())

            if int(item['CurrentPosition']) == 1:
                return

            try:
                played = float(item['CurrentPosition'] * 10000000) / int(item['Runtime']) * 100
            except ZeroDivisionError: # Runtime is 0.
                played = 0

            if played > 2.0 and not self.up_next:

                self.up_next = True
                self.next_up()

            if (item['CurrentPosition'] - previous) < 30:

                return


        result = JSONRPC('Application.GetProperties').execute({'properties': ["volume", "muted"]})
        result = result.get('result', {})
        item['Volume'] = result.get('volume')
        item['Muted'] = result.get('muted')
        item['CurrentPosition'] = int(self.getTime())
        self.detect_audio_subs(item)

        data = {
            'QueueableMediaTypes': "Video,Audio",
            'CanSeek': True,
            'ItemId': item['Id'],
            'MediaSourceId': item['MediaSourceId'],
            'PlayMethod': item['PlayMethod'],
            'VolumeLevel': item['Volume'],
            'PositionTicks': int(item['CurrentPosition'] * 10000000),
            'IsPaused': item['Paused'],
            'IsMuted': item['Muted'],
            'PlaySessionId': item['PlaySessionId'],
            'AudioStreamIndex': item['AudioStreamIndex'],
            'SubtitleStreamIndex': item['SubtitleStreamIndex']
        }
        item['Server']['api'].session_progress(data)

    def onPlayBackStopped(self):
        
        ''' Will be called when user stops playing a file.
        '''
        window('emby_play', clear=True)
        self.stop_playback()
        LOG.debug("--<[ playback ]")

    def onPlayBackEnded(self):
        
        ''' Will be called when kodi stops playing a file.
        '''
        self.stop_playback()
        LOG.debug("--<<[ playback ]")

    def stop_playback(self):
        
        ''' Stop all playback. Check for external player for positionticks.
        '''
        if not self.played:
            return

        LOG.info("Played info: %s", self.played)

        for file in self.played:
            item = self.played[file]

            if item:
                window('emby.skip.%s.bool' % item['Id'], True)

                if window('emby.external.bool'):
                    window('emby.external', clear=True)

                    if int(item['CurrentPosition']) == 1:
                        item['CurrentPosition'] = int(item['Runtime'])

                data = {
                    'ItemId': item['Id'],
                    'MediaSourceId': item['MediaSourceId'],
                    'PositionTicks': int(item['CurrentPosition'] * 10000000),
                    'PlaySessionId': item['PlaySessionId']
                }
                item['Server']['api'].session_stop(data)

                if item.get('LiveStreamId'):
                    item['Server']['api'].close_live_stream(item['LiveStreamId'])

                elif item['PlayMethod'] == 'Transcode':

                    LOG.info("<[ transcode/%s ]", item['Id'])
                    item['Server']['api'].close_transcode(item['DeviceId'])


                path = xbmc.translatePath("special://profile/addon_data/plugin.video.emby/temp/").decode('utf-8')

                if xbmcvfs.exists(path):
                    dirs, files = xbmcvfs.listdir(path)

                    for file in files:
                        xbmcvfs.delete(os.path.join(path, file.decode('utf-8')))

                result = item['Server']['api'].get_item(item['Id']) or {}

                if 'UserData' in result and result['UserData']['Played']:
                    delete = False

                    if result['Type'] == 'Episode' and settings('deleteTV.bool'):
                        delete = True
                    elif result['Type'] == 'Movie' and settings('deleteMovies.bool'):
                        delete = True

                    if not settings('offerDelete.bool'):
                        delete = False

                    if delete:

                        if dialog("yesno", heading=_(30091), line1=_(33015), autoclose=120000):
                            item['Server']['api'].delete_item(item['Id'])

                window('emby.external_check', clear=True)

        self.played.clear()