#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, unicode_literals
from logging import getLogger
from urllib import quote_plus, unquote
import requests

from .kodi_db import KodiVideoDB, KodiMusicDB, KodiTextureDB
from . import app, backgroundthread, utils

LOG = getLogger('PLEX.artwork')

# Disable annoying requests warnings
requests.packages.urllib3.disable_warnings()

# Potentially issues with limited number of threads Hence let Kodi wait till
# download is successful
TIMEOUT = (35.1, 35.1)
BATCH_SIZE = 500

IMAGE_CACHING_SUSPENDS = []


def double_urlencode(text):
    return quote_plus(quote_plus(text))


def double_urldecode(text):
    return unquote(unquote(text))


class ImageCachingThread(backgroundthread.KillableThread):
    def isSuspended(self):
        return any(IMAGE_CACHING_SUSPENDS)

    def _url_generator(self, kind, kodi_type):
        """
        Main goal is to close DB connection between calls
        """
        offset = 0
        i = 0
        while True:
            batch = []
            with kind(texture_db=True) as kodidb:
                texture_db = KodiTextureDB(kodiconn=kodidb.kodiconn,
                                           artconn=kodidb.artconn,
                                           lock=False)
                for i, url in enumerate(kodidb.artwork_generator(kodi_type,
                                                                 BATCH_SIZE,
                                                                 offset)):
                    if texture_db.url_not_yet_cached(url):
                        batch.append(url)
                        if len(batch) == BATCH_SIZE:
                            break
            offset += i
            for url in batch:
                yield url
            if i + 1 < BATCH_SIZE:
                break

    def run(self):
        LOG.info("---===### Starting ImageCachingThread ###===---")
        try:
            self._run()
        except:
            utils.ERROR()
        finally:
            LOG.info("---===### Stopped ImageCachingThread ###===---")

    def _run(self):
        kinds = [KodiVideoDB]
        if app.SYNC.enable_music:
            kinds.append(KodiMusicDB)
        for kind in kinds:
            for kodi_type in ('poster', 'fanart'):
                for url in self._url_generator(kind, kodi_type):
                    if self.isCanceled():
                        return
                    while self.isSuspended():
                        # Set in service.py
                        if self.isCanceled():
                            # Abort was requested while waiting. We should exit
                            return
                        app.APP.monitor.waitForAbort(1)
                    cache_url(url)
        # Toggles Image caching completed to Yes
        utils.settings('plex_status_image_caching', value=utils.lang(107))


def cache_url(url):
    url = double_urlencode(utils.try_encode(url))
    sleeptime = 0
    while True:
        try:
            requests.head(
                url="http://%s:%s/image/image://%s"
                    % (app.CONN.webserver_host,
                       app.CONN.webserver_port,
                       url),
                auth=(app.CONN.webserver_username,
                      app.CONN.webserver_password),
                timeout=TIMEOUT)
        except requests.Timeout:
            # We don't need the result, only trigger Kodi to start the
            # download. All is well
            break
        except requests.ConnectionError:
            if app.APP.stop_pkc:
                # Kodi terminated
                break
            # Server thinks its a DOS attack, ('error 10053')
            # Wait before trying again
            if sleeptime > 5:
                LOG.error('Repeatedly got ConnectionError for url %s',
                          double_urldecode(url))
                break
            LOG.debug('Were trying too hard to download art, server '
                      'over-loaded. Sleep %s seconds before trying '
                      'again to download %s',
                      2**sleeptime, double_urldecode(url))
            app.APP.monitor.waitForAbort((2**sleeptime))
            sleeptime += 1
            continue
        except Exception as err:
            LOG.error('Unknown exception for url %s: %s'.
                      double_urldecode(url), err)
            import traceback
            LOG.error("Traceback:\n%s", traceback.format_exc())
            break
        # We did not even get a timeout
        break