import sys
import json
import base64
import six

from six.moves import urllib_request
from six.moves import urllib_parse
from six.moves.http_cookiejar import CookieJar

from elementum.util import notify, getElementumLocalizedString
from elementum.logger import log
from elementum.config import ELEMENTUMD_HOST
from elementum.addon import ADDON, ADDON_ID

from kodi_six.utils import py2_decode, py2_encode, PY2

RESOLUTION_UNKNOWN = 0
RESOLUTION_480P = 1
RESOLUTION_720P = 2
RESOLUTION_1080P = 3
RESOLUTION_1440P = 4
RESOLUTION_4K2K = 5

RIP_UNKNOWN = 0
RIP_CAM = 1
RIP_TS = 2
RIP_TC = 3
RIP_SCR = 4
RIP_DVDSCR = 5
RIP_DVD = 6
RIP_HDTV = 7
RIP_WEB = 8
RIP_BLURAY = 9

RATING_UNKNOWN = 0
RATING_PROPER = 1
RATING_NUKED = 2

CODEC_UNKNOWN = 0
CODEC_XVID = 1
CODEC_H264 = 2
CODEC_H265 = 3
CODEC_MP3 = 4
CODEC_AAC = 5
CODEC_AC3 = 6
CODEC_DTS = 7
CODEC_DTSHD = 8
CODEC_DTSHDMA = 9

USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.66 Safari/537.36"

COOKIE_JAR = CookieJar()
urllib_request.install_opener(urllib_request.build_opener(urllib_request.HTTPCookieProcessor(COOKIE_JAR)))

class closing(object):
    def __init__(self, thing):
        self.thing = thing

    def __enter__(self):
        return self.thing

    def __exit__(self, *exc_info):
        self.thing.close()


def parse_json(data):
    try:
        import simplejson as json
    except ImportError:
        import json
    return json.loads(data)


def parse_xml(data):
    import xml.etree.ElementTree as ET
    return ET.fromstring(data)


def request(url, params={}, headers={}, data=None, method=None):
    if params:
        url = "".join([url, "?", urllib_parse.urlencode(params)])

    req = urllib_request.Request(url)
    if method:
        req.get_method = lambda: method
    req.add_header("User-Agent", USER_AGENT)
    req.add_header("Accept-Encoding", "gzip")
    for k, v in headers.items():
        req.add_header(k, v)
    if data:
        req.data = data
    try:
        with closing(urllib_request.urlopen(req)) as response:
            data = response.read()
            if response.headers.get("Content-Encoding", "") == "gzip":
                import zlib
                data = zlib.decompressobj(16 + zlib.MAX_WBITS).decompress(data)
            response.data = data
            response.json = lambda: parse_json(data)
            response.xml = lambda: parse_xml(data)
            return response
    except Exception as e:
        log.error("Could not open url %s: %s" % (url, e))
        import traceback
        map(log.error, traceback.format_exc().split("\n"))
        notify(py2_encode("%s: %s" % (getElementumLocalizedString(30224), repr(e)), 'utf-8'))
        return None, None


HEAD = lambda *args, **kwargs: request(*args, method="HEAD", **kwargs)
GET = lambda *args, **kwargs: request(*args, method="GET", **kwargs)
POST = lambda *args, **kwargs: request(*args, method="POST", **kwargs)
PUT = lambda *args, **kwargs: request(*args, method="PUT", **kwargs)
DELETE = lambda *args, **kwargs: request(*args, method="DELETE", **kwargs)


def append_headers(uri, headers):
    return uri + "|" + "|".join(["%s=%s" % h for h in headers.items()])


def with_cookies(uri):
    return uri + "|Cookie=" + "; ".join(["%s=%s" % (c.name, c.value) for c in COOKIE_JAR])


def extract_magnets(data):
    import re
    for magnet in re.findall(r'magnet:\?[^\'"\s<>\[\]]+', data):
        yield {"uri": magnet}


# Borrowed from xbmcswift2
def get_setting(key, converter=str, choices=None):
    value = ADDON.getSetting(id=key)
    if isinstance(choices, (list, tuple)):
        if not value:
            value = 0
        return choices[int(value)]
    elif converter is six.text_type or converter is str:
        return py2_decode(value)
    elif converter is bool:
        return value == 'true'
    elif converter is int:
        if not value:
            value = 0
        return int(value)
    else:
        raise TypeError('Acceptable converters are str, unicode, bool and '
                        'int. Acceptable choices are instances of list '
                        ' or tuple.')


def set_setting(key, val):
    return ADDON.setSetting(id=key, value=val)


def register(search, search_movie, search_episode, search_season=None):
    try:
        payload = json.loads(base64.b64decode(sys.argv[1]))
    except:
        notify(getElementumLocalizedString(30102), time=1000)
        return

    results = ()
    method = {
        "search": search,
        "search_movie": search_movie,
        "search_season": search_season,
        "search_episode": search_episode,
    }.get(payload["method"]) or (lambda *a, **kw: [])
    try:
        results = ()
        try:
            objects = method(payload["search_object"])
            if objects is not None:
                results = tuple(objects)
        except Exception as e:
            import traceback
            map(log.error, traceback.format_exc().split("\n"))
            notify(py2_encode("%s: %s" % (getElementumLocalizedString(30224), repr(e)), 'utf-8'))
            try:
                urllib_request.urlopen("%s/provider/%s/failure" % (ELEMENTUMD_HOST, ADDON_ID))
            except:
                pass
    finally:
        try:
            req_data = json.dumps(results)
            if not PY2 and isinstance(req_data, str):
                req_data = req_data.encode()
            req = urllib_request.Request(payload["callback_url"], data=req_data)
            callback_user = payload.get("callback_login")
            callback_password = payload.get("callback_password")
            if callback_user or callback_password:
                base64string = base64.b64encode('{}:{}'.format(callback_user, callback_password).encode())
                req.add_header("Authorization", "Basic %s" % base64string.decode('utf-8'))
            with closing(urllib_request.urlopen(req)) as response:
                log.debug("callback returned: %d" % response.getcode())
        except Exception as e:
            import traceback
            log.error("Could not open url %s: %s" % (payload["callback_url"], e))
            map(log.error, traceback.format_exc().split("\n"))
            notify(py2_encode("%s: %s" % (getElementumLocalizedString(30224), repr(e)), 'utf-8'))
            try:
                urllib_request.urlopen("%s/provider/%s/failure" % (ELEMENTUMD_HOST, ADDON_ID))
            except:
                pass
