# -*- coding: utf-8 -*-
from __future__ import division, absolute_import, print_function, unicode_literals

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

import json
import os

from six import iteritems, ensure_text

from ..helper import LazyLogger, get_filesystem_encoding

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

LOG = LazyLogger(__name__)

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


class Objects(object):

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

    def __init__(self):

        ''' Hold all persistent data here.
        '''

        self.__dict__ = self._shared_state

    def mapping(self):

        ''' Load objects mapping.
        '''
        file_dir = os.path.dirname(ensure_text(__file__, get_filesystem_encoding()))

        with open(os.path.join(file_dir, 'obj_map.json')) as infile:
            self.objects = json.load(infile)

    def map(self, item, mapping_name):

        ''' Syntax to traverse the item dictionary.
            This of the query almost as a url.

            Item is the Jellyfin item json object structure

            ",": each element will be used as a fallback until a value is found.
            "?": split filters and key name from the query part, i.e. MediaSources/0?$Name
            "$": lead the key name with $. Only one key value can be requested per element.
            ":": indicates it's a list of elements [], i.e. MediaSources/0/MediaStreams:?$Name
                 MediaStreams is a list.
            "/": indicates where to go directly
        '''
        self.mapped_item = {}

        if not mapping_name:
            raise Exception("execute mapping() first")

        mapping = self.objects[mapping_name]

        for key, value in iteritems(mapping):

            self.mapped_item[key] = None
            params = value.split(',')

            for param in params:

                obj = item
                obj_param = param
                obj_key = ""
                obj_filters = {}

                if '?' in obj_param:

                    if '$' in obj_param:
                        obj_param, obj_key = obj_param.rsplit('$', 1)

                    obj_param, filters = obj_param.rsplit('?', 1)

                    if filters:
                        for filter in filters.split('&'):
                            filter_key, filter_value = filter.split('=')
                            obj_filters[filter_key] = filter_value

                if ':' in obj_param:
                    result = []

                    for d in self.__recursiveloop__(obj, obj_param):

                        if not obj_filters or self.__filters__(d, obj_filters):
                            result.append(d)

                    obj = result
                    obj_filters = {}

                elif '/' in obj_param:
                    obj = self.__recursive__(obj, obj_param)

                elif obj is item and obj is not None:
                    obj = item.get(obj_param)

                if obj_filters and obj and not self.__filters__(obj, obj_filters):
                    obj = None

                if obj is None and len(params) != params.index(param):
                    continue

                if obj_key:
                    obj = [d[obj_key] for d in obj if d.get(obj_key)] if type(obj) == list else obj.get(obj_key)

                self.mapped_item[key] = obj
                break

        if not mapping_name.startswith('Browse') and not mapping_name.startswith('Artwork') and not mapping_name.startswith('UpNext'):

            self.mapped_item['ProviderName'] = self.objects.get('%sProviderName' % mapping_name)
            self.mapped_item['Checksum'] = json.dumps(item['UserData'])

        return self.mapped_item

    def __recursiveloop__(self, obj, keys):

        first, rest = keys.split(':', 1)
        obj = self.__recursive__(obj, first)

        if obj:
            for item in obj:
                if rest:
                    self.__recursiveloop__(item, rest)
                else:
                    yield item

    def __recursive__(self, obj, keys):

        for string in keys.split('/'):

            if not obj:
                return

            obj = obj[int(string)] if string.isdigit() else obj.get(string)

        return obj

    def __filters__(self, obj, filters):

        result = False

        for key, value in iteritems(filters):

            inverse = False

            if value.startswith('!'):

                inverse = True
                value = value.split('!', 1)[1]

            if value.lower() == "null":
                value = None

            result = obj.get(key) != value if inverse else obj.get(key) == value

        return result
