import os
import threading
import json
import uuid
import xbmc
import xbmcgui
import xbmcvfs
from helper import utils, player, queue
from emby import listitem
from database import dbio

ThemePlayerId = 0
ThemeKodiId = ""
ThemeKodiType = ""
ThemeKodiParentType = ""
ThemeKodiParentId = ""
VolumeFade = player.Volume
ThemeQueue = queue.Queue()
RestoreBusy = threading.Lock()
ThemeBusy = threading.Lock()
TerminateTheme = False
TerminateRestore = False


def monitor_Themes():
    xbmc.log("EMBY.hooks.themes: THREAD: --->[ Monitor themes ]", 0) # LOGDEBUG
    KodiTypeOld = ""
    KodiIdOld = ""
    utils.start_thread(ThemePlay, ())

    while True:
        if not utils.theme_enable_audio and not utils.theme_enable_video:
            if utils.sleep(2):
                ThemeQueue.put("QUIT")
                xbmc.log("EMBY.monitor.themes: THREAD: ---<[ Monitor themes ]", 0) # LOGDEBUG
                return

            continue

        # Check if regular content is playing
        if utils.RemoteMode or (player.PlayItem[0] and (player.PlayItem[0] != ThemeKodiId or player.PlayItem[1] != ThemeKodiType) or player.VideoPlayback not in ("READY", "THEME") or player.Trailers):
            globals().update({"ThemePlayerId": 0, "ThemeKodiParentId": "", "ThemeKodiParentType": "", "ThemeKodiId": "", "ThemeKodiType": ""})
            KodiIdOld = ""
            KodiTypeOld = ""

            if utils.sleep(3):
                ThemeQueue.put("QUIT")
                xbmc.log("EMBY.monitor.themes: THREAD: ---<[ Monitor themes ]", 0) # LOGDEBUG
                return

            continue

        # Wait 1 second for navigation end
        KodiTypeCompare, KodiIdCompare = get_KodiIds()
        ThemePlayThreadDelay = 0

        while ThemePlayThreadDelay < 10:
            ThemePlayThreadDelay += 1

            if utils.sleep(utils.theme_delay):
                ThemeQueue.put("QUIT")
                xbmc.log("EMBY.monitor.themes: THREAD: ---<[ Monitor themes ]", 0) # LOGDEBUG
                return

            KodiType, KodiId = get_KodiIds()

            if KodiTypeCompare != KodiType or KodiIdCompare != KodiId:
                break
        else: # no break triggered
            # Check if item has changed
            if KodiIdOld != KodiId or KodiTypeOld != KodiType:
                KodiIdOld = KodiId
                KodiTypeOld = KodiType

                # Ignore homescreen
                if not utils.theme_enable_homescreen and xbmc.getCondVisibility('Window.IsActive(10000)') or xbmc.getCondVisibility('Window.IsActive(12005)') or xbmc.getCondVisibility('Window.IsActive(12006)') or xbmc.getCondVisibility('Window.IsActive(10142)'):  # skip fullscreenvideo, visualisation, fullscreeninfo
                    continue

                # Terminate previous processes
                if RestoreBusy.locked():
                    globals()['TerminateRestore'] = True

                if ThemeBusy.locked():
                    globals()['TerminateTheme'] = True

                # Run commands
                if ThemeKodiId and KodiId == ThemeKodiParentId and KodiType == ThemeKodiParentType:
                    ThemeQueue.put("FADE")
                else:
                    ThemeQueue.put(((KodiType, KodiId),))

# Player events (queued by monitor notifications)
def ThemePlay():
    xbmc.log("EMBY.monitor.themes: THREAD: --->[ ThemePlay ]", 0) # LOGDEBUG

    while True:
        ThemeReceived = ThemeQueue.get()

        if ThemeReceived == "QUIT":
            xbmc.log("EMBY.monitor.themes: THREAD: ---<[ ThemePlay ]", 0) # LOGDEBUG
            return

        if ThemeReceived == "FADE":
            with ThemeBusy: # Wait for cancel
                pass

            with RestoreBusy:
                restore_Volume()
                globals()['TerminateRestore'] = False
        else:
            with RestoreBusy: # Wait for cancel
                pass

            with ThemeBusy:
                if PlaybackStop():
                    if ThemeReceived[0] and ThemeReceived[1]:
                        PlaybackStart(ThemeReceived[0], ThemeReceived[1])

                globals()['TerminateTheme'] = False

def PlaybackStart(PlayKodiType, PlayKodiId):
    if PlayKodiType not in ("movie", "tvshow"):
        return

    EmbyId = ""
    ServerId = ""
    EmbyServer = None
    EmbyType = utils.KodiTypeMapping[PlayKodiType]

    for ServerId, EmbyServer in list(utils.EmbyServers.items()):
        EmbyDB = dbio.DBOpenRO(ServerId, "Theme")

        if utils.theme_enable_audio and utils.theme_enable_video: # Both
            if utils.theme_priority == "audio":
                EmbyId, EmbyMetaData = EmbyDB.get_ThemeAudio_by_KodiId_EmbyType(PlayKodiId, EmbyType)
                PlayerId = 0

                if not EmbyId:
                    EmbyId, EmbyMetaData = EmbyDB.get_ThemeVideo_by_KodiId_EmbyType(PlayKodiId, EmbyType)
                    PlayerId = 1
            else:
                EmbyId, EmbyMetaData = EmbyDB.get_ThemeVideo_by_KodiId_EmbyType(PlayKodiId, EmbyType)
                PlayerId = 1

                if not EmbyId:
                    EmbyId, EmbyMetaData = EmbyDB.get_ThemeAudio_by_KodiId_EmbyType(PlayKodiId, EmbyType)
                    PlayerId = 0
        elif utils.theme_enable_audio: # Audio only
            EmbyId, EmbyMetaData = EmbyDB.get_ThemeAudio_by_KodiId_EmbyType(PlayKodiId, EmbyType)
            PlayerId = 0
        else: # Video only
            EmbyId, EmbyMetaData = EmbyDB.get_ThemeVideo_by_KodiId_EmbyType(PlayKodiId, EmbyType)
            PlayerId = 1

        dbio.DBCloseRO(ServerId, "Theme")

        if EmbyId:
            break

    del EmbyDB

    if EmbyId:
        if player.PlayItem[0] and (player.PlayItem[0] != ThemeKodiId or player.PlayItem[1] != ThemeKodiType) or player.VideoPlayback not in ("READY", "THEME") or player.Trailers:
            return

        Item = json.loads(EmbyMetaData)
        MediaSourceId = Item['MediaSources'][0]['Id']
        PlaySessionId = str(uuid.uuid4()).replace("-", "")
        Path = os.path.join(utils.DownloadPath, "EMBY-themes", "")
        ThemeFile = xbmcvfs.translatePath(f"{Path}{ServerId}_{Item['Id']}.{Item.get('Container', 'ukn')}") # Downloaded theme

        if not xbmcvfs.exists(ThemeFile): # remote theme
            ThemeFile = f"{EmbyServer.ServerData['ServerUrl']}/emby/videos/{EmbyId}/stream?static=true&MediaSourceId={MediaSourceId}&PlaySessionId={PlaySessionId}&DeviceId={EmbyServer.ServerData['DeviceId']}&api_key={EmbyServer.ServerData['AccessToken']}|seekable=0&ignore_cache=1&failonerror=false&verifypeer=false" # seekable=0 must be set -> Kodi uses playerid -1 and not touching playlists

        player.QueuedPlayingItem = [{'QueueableMediaTypes': ["Audio", "Video", "Photo"], 'CanSeek': True, 'IsPaused': False, 'ItemId': int(EmbyId), 'MediaSourceId': MediaSourceId, 'PlaySessionId': PlaySessionId, 'PositionTicks': 0, 'RunTimeTicks': 0, 'VolumeLevel': player.Volume, 'PlaybackRate': 1, 'Shuffle': False, 'RepeatMode': "RepeatNone", 'IsMuted': False}, None, None, None, EmbyServer, ThemePlayerId, "", ""]
        ListItem = listitem.set_ListItem(Item, ServerId)
        ListItem.setPath(ThemeFile)
        globals()['VolumeFade'] = 0

        if TerminateTheme:
            return

        if PlayerId:
            globals().update({"ThemePlayerId": PlayerId, "ThemeKodiParentId": PlayKodiId, "ThemeKodiParentType": PlayKodiType, "ThemeKodiId": Item['KodiId'], "ThemeKodiType": "video"})
        else:
            globals().update({"ThemePlayerId": PlayerId, "ThemeKodiParentId": PlayKodiId, "ThemeKodiParentType": PlayKodiType, "ThemeKodiId": Item['KodiId'], "ThemeKodiType": "song"})

        if PlayerId == 1:
            player.CloseDialog = True

        if player.PlayItem[0] and (player.PlayItem[0] != ThemeKodiId or player.PlayItem[1] != ThemeKodiType) or player.VideoPlayback not in ("READY", "THEME") or player.Trailers:
            return

        player.VideoPlayback = "THEME"
        player.XbmcPlayer.play(item=ThemeFile, listitem=ListItem, windowed=True)
        del ListItem

        # Wait for playback start
        while not player.PlayItem[0]:
            if utils.sleep(0.01):
                return

        xbmc.executebuiltin('Dialog.Close(all, true)')

        # Fade volume
        if utils.theme_fade_in:
            VolumeOld = player.Volume
            xbmc.executebuiltin("SetVolume(0)", True)

            while VolumeFade != VolumeOld:
                if TerminateTheme:
                    break

                globals()['VolumeFade'] += 1
                xbmc.executebuiltin(f"SetVolume({VolumeFade})", True)

                if not check_ThemePlaying() or utils.sleep(utils.theme_fade_in):
                    xbmc.executebuiltin(f"SetVolume({VolumeOld})", True)
                    break

            player.Volume = VolumeOld

def PlaybackStop():
    # No theme played
    if not ThemeKodiId:
        return True

    if utils.theme_fade_out:
        VolumeOld = player.Volume

        while VolumeFade:
            globals()['VolumeFade'] -= 1
            xbmc.executebuiltin(f"SetVolume({VolumeFade})", True)

            if not check_ThemePlaying() or utils.sleep(utils.theme_fade_out):
                xbmc.executebuiltin(f"SetVolume({VolumeOld})", True)
                player.Volume = VolumeOld
                return False

            if TerminateTheme:
                player.Volume = VolumeOld
                return False

    utils.SendJson(f'{{"jsonrpc":"2.0","method":"Player.Stop","params":{{"playerid":{ThemePlayerId}}},"id":1}}', True)
    globals().update({"ThemePlayerId": 0, "ThemeKodiParentId": "", "ThemeKodiParentType": "", "ThemeKodiId": "", "ThemeKodiType": ""})
    Counter = 0

    while player.PlayItem[0] or Counter < 10:
        Counter += 1 # Kodi workaround, Kodi's playback stop indicator is not accurate. Wait at least 1 second

        if utils.sleep(0.1):
            break

    if utils.theme_fade_out:
        xbmc.executebuiltin(f"SetVolume({VolumeOld})", False)
        player.Volume = VolumeOld

    return True

def restore_Volume():
    if utils.theme_fade_in:
        VolumeOld = player.Volume

        while VolumeFade != VolumeOld:
            if TerminateRestore:
                break

            globals()['VolumeFade'] += 1
            xbmc.executebuiltin(f"SetVolume({VolumeFade})", False)

            if not check_ThemePlaying() or utils.sleep(utils.theme_fade_in):
                xbmc.executebuiltin(f"SetVolume({VolumeOld})", False)
                break

        player.Volume = VolumeOld

def check_ThemePlaying():
    if not player.PlayItem[0] or player.PlayItem[0] != ThemeKodiId or player.PlayItem[1] != ThemeKodiType:
        globals().update({"ThemePlayerId": 0, "ThemeKodiParentId": "", "ThemeKodiParentType": "", "ThemeKodiId": "", "ThemeKodiType": ""})
        return False

    return True

def get_KodiIds():
    Result = utils.SendJson('{"jsonrpc":"2.0","method":"XBMC.GetInfoLabels","params":{"labels": ["ListItem.DBTYPE", "ListItem.DBID", "ListItem.TVShowDBID"]},"id":1}', True).get("result", {})

    if Result:
        KodiType = Result.get("ListItem.DBTYPE", "")
        KodiTVShowId = Result.get("ListItem.TVShowDBID", "")

        if KodiType in ("episode", "season"): # get seeriesid
            KodiId = KodiTVShowId
            KodiType = "tvshow"
        else:
            KodiId = Result.get("ListItem.DBID", "")

        return KodiType, KodiId

    return "", 0

def download():
    utils.close_dialog("addoninformation")
    DownloadAudioThemes = False
    DownloadVideoThemes = False
    Path = os.path.join(utils.DownloadPath, "EMBY-themes", "")
    utils.mkDir(Path)
    DownloadAudioThemes = utils.Dialog.yesno(heading=utils.addon_name, message=utils.Translate(33758), yeslabel=utils.Translate(33760), nolabel=utils.Translate(33761), defaultbutton=11) # defaultbutton=11 = yes
    DownloadVideoThemes = utils.Dialog.yesno(heading=utils.addon_name, message=utils.Translate(33759), yeslabel=utils.Translate(33760), nolabel=utils.Translate(33761), defaultbutton=10) # defaultbutton=10 = no

    if not DownloadAudioThemes and not DownloadVideoThemes:
        return

    ProgressBar = xbmcgui.DialogProgressBG()
    ProgressBar.create(utils.Translate(33199), utils.Translate(33451))
    Themes = []

    for ServerId, EmbyServer in list(utils.EmbyServers.items()):
        EmbyDB = dbio.DBOpenRO(ServerId, "ThemeDownload")

        if DownloadAudioThemes:
            Themes += EmbyDB.get_ThemeAudio()

        if DownloadVideoThemes:
            Themes += EmbyDB.get_ThemeVideo()

        dbio.DBCloseRO(ServerId, "ThemeDownload")
        TotalItems = len(Themes) / 100

        for Index, Trailer in enumerate(Themes):
            Item = json.loads(Trailer[1])
            ProgressBar.update(int(Index / TotalItems), utils.Translate(33451), str(Trailer))
            FilePath = xbmcvfs.translatePath(f"{Path}{ServerId}_{Trailer[0]}.{Item.get('Container', 'ukn')}")

            if not xbmcvfs.exists(FilePath):
                FolderPath = xbmcvfs.translatePath(Path)

                if 'Size' not in Item or not Item['Size']:
                    xbmc.log(f"EMBY.monitor.themes: Theme has no filesize: {Item}", 3) # LOGERROR
                    continue

                EmbyServer.API.download_file(Trailer[0], "", FolderPath, FilePath, Item['Size'], Item['Id'], "", "", "", "")
            else:
                xbmc.log(f"EMBY.monitor.themes: Theme exists: {FilePath}", 0) # LOGDEBUG

    ProgressBar.close()
    del ProgressBar
    utils.Dialog.notification(heading=utils.addon_name, message=utils.Translate(33153), icon=utils.icon, time=utils.displayMessage, sound=False)
