#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
The Plex Companion master python file
"""
from logging import getLogger

import xbmc

from ..plex_api import API
from .. import utils
from ..utils import cast
from .. import plex_functions as PF
from .. import playlist_func as PL
from .. import playback
from .. import json_rpc as js
from .. import variables as v
from .. import app
from .. import exceptions


log = getLogger('PLEX.companion.processing')


def update_playqueue_from_PMS(playqueue,
                              playqueue_id=None,
                              repeat=None,
                              offset=None,
                              transient_token=None,
                              start_plex_id=None):
    """
    Completely updates the Kodi playqueue with the new Plex playqueue. Pass
    in playqueue_id if we need to fetch a new playqueue

    repeat = 0, 1, 2
    offset = time offset in Plextime (milliseconds)
    """
    log.info('New playqueue %s received from Plex companion with offset '
             '%s, repeat %s, start_plex_id %s',
             playqueue_id, offset, repeat, start_plex_id)
    # Safe transient token from being deleted
    if transient_token is None:
        transient_token = playqueue.plex_transient_token
    with app.APP.lock_playqueues:
        try:
            xml = PL.get_PMS_playlist(playqueue, playqueue_id)
        except exceptions.PlaylistError:
            log.error('Could now download playqueue %s', playqueue_id)
            return
        if playqueue.id == playqueue_id:
            # This seems to be happening ONLY if a Plex Companion device
            # reconnects and Kodi is already playing something - silly, really
            # For all other cases, a new playqueue is generated by Plex
            log.debug('Update for existing playqueue detected')
            return
        playqueue.clear()
        # Get new metadata for the playqueue first
        try:
            PL.get_playlist_details_from_xml(playqueue, xml)
        except exceptions.PlaylistError:
            log.error('Could not get playqueue ID %s', playqueue_id)
            return
        playqueue.repeat = 0 if not repeat else int(repeat)
        playqueue.plex_transient_token = transient_token
        playback.play_xml(playqueue,
                          xml,
                          offset=offset,
                          start_plex_id=start_plex_id)


def process_node(key, transient_token, offset):
    """
    E.g. watch later initiated by Companion. Basically navigating Plex
    """
    app.CONN.plex_transient_token = transient_token
    params = {
        'mode': 'plex_node',
        'key': f'{{server}}{key}',
        'offset': offset
    }
    handle = f'RunPlugin(plugin://{utils.extend_url(v.ADDON_ID, params)})'
    xbmc.executebuiltin(handle)


def process_playlist(containerKey, typus, key, offset, token):
    # Get the playqueue ID
    _, container_key, query = PF.ParseContainerKey(containerKey)
    try:
        playqueue = app.PLAYQUEUES.from_plex_type(typus)
    except ValueError:
        # E.g. Plex web does not supply the media type
        # Still need to figure out the type (video vs. music vs. pix)
        xml = PF.GetPlexMetadata(key)
        try:
            xml[0].attrib
        except (AttributeError, IndexError, TypeError):
            log.error('Could not download Plex metadata')
            return
        api = API(xml[0])
        playqueue = app.PLAYQUEUES.from_plex_type(api.plex_type)
    if key:
        _, key, _ = PF.ParseContainerKey(key)
    update_playqueue_from_PMS(playqueue,
                              playqueue_id=container_key,
                              repeat=query.get('repeat'),
                              offset=utils.cast(int, offset),
                              transient_token=token,
                              start_plex_id=key)


def process_streams(plex_type, video_stream_id, audio_stream_id,
                    subtitle_stream_id):
    """
    Plex Companion client adjusted audio or subtitle stream
    """
    playqueue = app.PLAYQUEUES.from_plex_type(plex_type)
    pos = js.get_position(playqueue.playlistid)
    playqueue.items[pos].on_plex_stream_change(video_stream_id,
                                               audio_stream_id,
                                               subtitle_stream_id)


def process_refresh(playqueue_id):
    """
    example data: {'playQueueID': '8475', 'commandID': '11'}
    """
    xml = PL.get_pms_playqueue(playqueue_id)
    if xml is None:
        return
    if len(xml) == 0:
        log.debug('Empty playqueue received - clearing playqueue')
        plex_type = PL.get_plextype_from_xml(xml)
        if plex_type is None:
            return
        playqueue = app.PLAYQUEUES.from_plex_type(plex_type)
        playqueue.clear()
        return
    playqueue = app.PLAYQUEUES.from_plex_type(xml[0].attrib['type'])
    update_playqueue_from_PMS(playqueue, playqueue_id)


def skip_to(playqueue_item_id, key):
    """
    Skip to a specific playlist position.

    Does not seem to be implemented yet by Plex!
    """
    _, plex_id = PF.GetPlexKeyNumber(key)
    log.debug('Skipping to playQueueItemID %s, plex_id %s',
              playqueue_item_id, plex_id)
    found = True
    for player in list(js.get_players().values()):
        playqueue = app.PLAYQUEUES[player['playerid']]
        for i, item in enumerate(playqueue.items):
            if item.id == playqueue_item_id:
                found = True
                break
        else:
            for i, item in enumerate(playqueue.items):
                if item.plex_id == plex_id:
                    found = True
                    break
        if found is True:
            app.APP.player.play(playqueue.kodi_pl, None, False, i)
        else:
            log.error('Item not found to skip to')


def process_proxy_xml(cmd):
    """cmd: a "Command" etree xml"""
    path = cmd.get('path')
    if (path == '/player/playback/playMedia'
            and cmd.get('queryAddress') == 'node.plexapp.com'):
        process_node(cmd.get('queryKey'),
                     cmd.get('queryToken'),
                     cmd.get('queryOffset') or 0)
    elif path == '/player/playback/playMedia':
        with app.APP.lock_playqueues:
            process_playlist(cmd.get('queryContainerKey'),
                             cmd.get('queryType'),
                             cmd.get('queryKey'),
                             cmd.get('queryOffset'),
                             cmd.get('queryToken'))
    elif path == '/player/playback/refreshPlayQueue':
        with app.APP.lock_playqueues:
            process_refresh(cmd.get('queryPlayQueueID'))
    elif path == '/player/playback/setParameters':
        if 'queryVolume' in cmd.attrib:
            js.set_volume(int(cmd.get('queryVolume')))
        else:
            log.error('Unknown command: %s: %s', cmd.tag, cmd.attrib)
    elif path == '/player/playback/play':
        js.play()
    elif path == '/player/playback/pause':
        js.pause()
    elif path == '/player/playback/stop':
        js.stop()
    elif path == '/player/playback/seekTo':
        js.seek_to(float(cmd.get('queryOffset', 0.0)) / 1000.0)
    elif path == '/player/playback/stepForward':
        js.smallforward()
    elif path == '/player/playback/stepBack':
        js.smallbackward()
    elif path == '/player/playback/skipNext':
        js.skipnext()
    elif path == '/player/playback/skipPrevious':
        js.skipprevious()
    elif path == '/player/playback/skipTo':
        skip_to(cmd.get('queryPlayQueueItemID'), cmd.get('queryKey'))
    elif path == '/player/navigation/moveUp':
        js.input_up()
    elif path == '/player/navigation/moveDown':
        js.input_down()
    elif path == '/player/navigation/moveLeft':
        js.input_left()
    elif path == '/player/navigation/moveRight':
        js.input_right()
    elif path == '/player/navigation/select':
        js.input_select()
    elif path == '/player/navigation/home':
        js.input_home()
    elif path == '/player/navigation/back':
        js.input_back()
    elif path == '/player/playback/setStreams':
        process_streams(cmd.get('queryType'),
                        cast(int, cmd.get('queryVideoStreamID')),
                        cast(int, cmd.get('queryAudioStreamID')),
                        cast(int, cmd.get('querySubtitleStreamID')))
    elif path == '/player/timeline/subscribe':
        pass
    elif path == '/player/timeline/unsubscribe':
        pass
    else:
        log.error('Unknown Plex companion path/command: %s: %s',
                  cmd.tag, cmd.attrib)
    return True
