import json
import os
import random
import string
import zlib
from itertools import dropwhile, islice

from metaflow.util import to_bytes


def _token_generator(token_prefix):
    for i in range(10000):
        prefix = "%s-%d-" % (token_prefix, i)
        # we need to use a consistent hash here, which is why
        # random.seed(prefix) or random.seed(hash(prefix)) won't work
        random.seed(zlib.adler32(to_bytes(prefix)))
        yield prefix + "".join(random.sample(string.ascii_lowercase, 4))


def _makedirs(path):
    # this is for python2 compatibility.
    # Python3 has os.makedirs(exist_ok=True).
    try:
        os.makedirs(path)
    except OSError as x:
        if x.errno == 17:
            return
        else:
            raise


def _load_config(path):
    if os.path.exists(path):
        with open(path) as f:
            return json.load(f)
    else:
        return {}


def _path(token_prefix):
    # TODO make this a MF config variable
    if os.environ.get("METAFLOW_TOKEN_HOME"):
        home = os.environ.get("METAFLOW_TOKEN_HOME")
    else:
        home = os.environ.get("METAFLOW_HOME", "~/.metaflowconfig")
    return os.path.expanduser("%s/%s" % (home, token_prefix))


def new_token(token_prefix, prev_token=None):
    if prev_token is None:
        for token in _token_generator(token_prefix):
            return token
    else:
        it = dropwhile(lambda x: x != prev_token, _token_generator(token_prefix))
        for _ in it:
            return next(it)
        else:
            return None


def load_token(token_prefix):
    config = _load_config(_path(token_prefix))
    return config.get("production_token")


def store_token(token_prefix, token):
    path = _path(token_prefix)
    config = _load_config(path)
    config["production_token"] = token
    _makedirs(os.path.dirname(path))
    with open(path, "w") as f:
        json.dump(config, f)
