# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, unicode_literals
from logging import getLogger
import xbmc

from . import common
from ..plex_api import API
from ..plex_db import PlexDB
from .. import backgroundthread, utils, kodidb_functions as kodidb
from .. import itemtypes, plex_functions as PF, variables as v, state


LOG = getLogger('PLEX.sync.fanart')

SUPPORTED_TYPES = (v.PLEX_TYPE_MOVIE, v.PLEX_TYPE_SHOW)
SYNC_FANART = utils.settings('FanartTV') == 'true'
PREFER_KODI_COLLECTION_ART = utils.settings('PreferKodiCollectionArt') == 'false'


class FanartThread(backgroundthread.KillableThread):
    """
    This will potentially take hours!
    """
    def __init__(self, callback, refresh=False):
        self.callback = callback
        self.refresh = refresh
        super(FanartThread, self).__init__()

    def isCanceled(self):
        return state.STOP_PKC

    def isSuspended(self):
        return state.SUSPEND_LIBRARY_THREAD or state.STOP_SYNC

    def run(self):
        try:
            self._run_internal()
        except:
            utils.ERROR(notify=True)

    def _run_internal(self):
        LOG.info('Starting FanartThread')
        with PlexDB() as plexdb:
            func = plexdb.every_plex_id if self.refresh else plexdb.missing_fanart
            for typus in SUPPORTED_TYPES:
                for plex_id in func(typus):
                    if self.isCanceled():
                        return
                    if self.isSuspended():
                        if self.isCanceled():
                            return
                        xbmc.sleep(1000)
                    process_fanart(plex_id, typus, self.refresh)
        LOG.info('FanartThread finished')
        self.callback()


class FanartTask(backgroundthread.Task, common.libsync_mixin):
    """
    This task will also be executed while library sync is suspended!
    """
    def setup(self, plex_id, plex_type, refresh=False):
        self.plex_id = plex_id
        self.plex_type = plex_type
        self.refresh = refresh

    def run(self):
        if self.isCanceled():
            return
        process_fanart(self.plex_id, self.plex_type, self.refresh)


def process_fanart(plex_id, plex_type, refresh=False):
    """
    Will look for additional fanart for the plex_type item with plex_id.
    Will check if we already got all artwork and only look if some are indeed
    missing.
    Will set the fanart_synced flag in the Plex DB if successful.
    """
    done = False
    try:
        artworks = None
        with PlexDB() as plexdb:
            db_item = plexdb.item_by_id(plex_id,
                                        plex_type)
        if not db_item:
            LOG.error('Could not get Kodi id for plex id %s', plex_id)
            return
        if not refresh:
            with kodidb.GetKodiDB('video') as kodi_db:
                artworks = kodi_db.get_art(db_item['kodi_id'],
                                           db_item['kodi_type'])
            # Check if we even need to get additional art
            for key in v.ALL_KODI_ARTWORK:
                if key not in artworks:
                    break
            else:
                done = True
                return
        xml = PF.GetPlexMetadata(plex_id)
        try:
            xml[0].attrib
        except (TypeError, IndexError, AttributeError):
            LOG.warn('Could not get metadata for %s. Skipping that item '
                     'for now', plex_id)
            return
        api = API(xml[0])
        if artworks is None:
            artworks = api.artwork()
        # Get additional missing artwork from fanart artwork sites
        artworks = api.fanart_artwork(artworks)
        with itemtypes.ITEMTYPE_FROM_PLEXTYPE[plex_type](None) as context:
            context.set_fanart(artworks,
                               db_item['kodi_id'],
                               db_item['kodi_type'])
        # Additional fanart for sets/collections
        if plex_type == v.PLEX_TYPE_MOVIE:
            for _, setname in api.collection_list():
                LOG.debug('Getting artwork for movie set %s', setname)
                with kodidb.GetKodiDB('video') as kodi_db:
                    setid = kodi_db.create_collection(setname)
                external_set_artwork = api.set_artwork()
                if external_set_artwork and PREFER_KODI_COLLECTION_ART:
                    kodi_artwork = api.artwork(kodi_id=setid,
                                               kodi_type=v.KODI_TYPE_SET)
                    for art in kodi_artwork:
                        if art in external_set_artwork:
                            del external_set_artwork[art]
                with itemtypes.Movie(None) as movie:
                    movie.artwork.modify_artwork(external_set_artwork,
                                                 setid,
                                                 v.KODI_TYPE_SET,
                                                 movie.kodicursor)
        done = True
    finally:
        if done is True:
            with PlexDB() as plexdb:
                plexdb.set_fanart_synced(plex_id,
                                         plex_type)