import re
import json
import zlib
import base64

def serialize(parsed_query):
    return base64.b64encode(
        zlib.compress(
            json.dumps(parsed_query).encode("utf-8")),
        altchars=b"-_").decode("utf-8")

def deserialize(url):

    string = url[2:]

    extension = None
    if "." in string:
        string, extension = string.split(".", 1)

    try:
        result = json.loads(
            zlib.decompress(
                base64.b64decode(string, altchars=b"-_")).decode("utf-8"))
    except zlib.error:
        return None

    if extension == "png":
        result["png_filename"] = url
        result["html_output"] = False

    return result


def metric_or_imperial(query, lang, us_ip=False):
    """
    """

    # what units should be used
    # metric or imperial
    # based on query and location source (imperial for US by default)
    if query.get('use_metric', False) and not query.get('use_imperial', False):
        query['use_imperial'] = False
        query['use_metric'] = True
    elif query.get('use_imperial', False) and not query.get('use_metric', False):
        query['use_imperial'] = True
        query['use_metric'] = False
    elif lang == 'us':
        # slack uses m by default, to override it speciy us.wttr.in
        query['use_imperial'] = True
        query['use_metric'] = False
    else:
        if us_ip:
            query['use_imperial'] = True
            query['use_metric'] = False
        else:
            query['use_imperial'] = False
            query['use_metric'] = True

    return query

def parse_query(args):
    result = {}

    reserved_args = ["lang"]

    q = ""

    for key, val in args.items():
        if len(val) == 0:
            q += key
            continue
        if val == 'True':
            val = True
        if val == 'False':
            val = False
        result[key] = val

    if q is None:
        return result
    if 'A' in q:
        result['force-ansi'] = True
    if 'n' in q:
        result['narrow'] = True
    if 'm' in q:
        result['use_metric'] = True
    if 'M' in q:
        result['use_ms_for_wind'] = True
    if 'u' in q:
        result['use_imperial'] = True
    if 'I' in q:
        result['inverted_colors'] = True
    if 't' in q:
        result['transparency'] = '150'
    if 'T' in q:
        result['no-terminal'] = True
    if 'p' in q:
        result['padding'] = True

    for days in "0123":
        if days in q:
            result['days'] = days

    if 'q' in q:
        result['no-caption'] = True
    if 'Q' in q:
        result['no-city'] = True
    if 'F' in q:
        result['no-follow-line'] = True

    for key, val in args.items():
        if val == 'True':
            val = True
        if val == 'False':
            val = False
        if val:
            result[key] = val

    # currently `view` is alias for `format`
    if "format" in result and not result.get("view"):
        result["view"] = result["format"]
        del result["format"]

    return result

def parse_wttrin_png_name(name):
    """
    Parse the PNG filename and return the result as a dictionary.
    For example:
        input = City_200x_lang=ru.png
        output = {
            "lang": "ru",
            "width": "200",
            "filetype": "png",
            "location": "City"
        }
    """

    parsed = {}
    to_be_parsed = {}

    if name.lower()[-4:] == '.png':
        parsed['filetype'] = 'png'
        name = name[:-4]

    parts = name.split('_')
    parsed['location'] = parts[0]

    one_letter_options = ""
    for part in parts[1:]:
        if re.match('(?:[0-9]+)x', part):
            parsed['width'] = part[:-1]
        elif re.match('x(?:[0-9]+)', part):
            parsed['height'] = part[1:]
        elif re.match(part, '(?:[0-9]+)x(?:[0-9]+)'):
            parsed['width'], parsed['height'] = part.split('x', 1)
        elif '=' in part:
            arg, val = part.split('=', 1)
            to_be_parsed[arg] = val
        else:
            one_letter_options += part

    for letter in one_letter_options:
        to_be_parsed[letter] = ''

    parsed.update(parse_query(to_be_parsed))

    # currently `view` is alias for `format`
    if "format" in parsed and not parsed.get("view"):
        parsed["view"] = parsed["format"]
        del parsed["format"]

    return parsed