import json

import boto3

from awsjar.utils import _data_dumper


class Jar:
    def __init__(self, *, lambda_name, region="", encoder=None, decoder=None):
        self.lambda_name = lambda_name

        if region:
            self.cl = boto3.client("lambda", region_name=region)
        else:
            self.cl = boto3.client("lambda")

        if not encoder:
            encoder = str

        def _dumps(data):
            return json.dumps(data, default=encoder)

        def _loads(data):
            return json.loads(data, object_hook=decoder)

        self._dumps = _dumps
        self._loads = _loads

    def get(self):
        """ Get state stored in Lambda environment variable."""
        env_vars = self._fetch_lambda_env_vars(self.lambda_name)
        state = env_vars.get("jar", "{}")
        state = self._loads(state)

        return state

    def put(self, data):
        """ Store state as Lambda environment variable under key 'jar'."""
        data = _data_dumper(data, self._dumps)

        env_vars = self._fetch_lambda_env_vars(self.lambda_name)
        env_vars["jar"] = data
        resp = self._update_function_config(self.lambda_name, env_vars)
        resp = resp.get("ResponseMetadata", {}).get("HTTPStatusCode", "")
        return resp

    def _fetch_lambda_env_vars(self, lambda_func_name):
        """ Fetch all Lambda environment variables."""
        resp = self.cl.get_function_configuration(FunctionName=lambda_func_name)

        try:
            env_vars = resp["Environment"]["Variables"]
        except KeyError:
            msg = f"Error getting Lambda env var, boto3 resp: {resp}"
            raise ValueError(msg)

        return env_vars

    def _update_function_config(self, func_name, env_vars):
        """ Update the Lambda with new enviroment variables """
        # import sys
        #
        # tstr = str(env_vars).replace('"', '\\"')
        # size = sys.getsizeof(tstr)
        #
        # print("sizeof str:", sys.getsizeof(tstr))
        # print("len    str:", len(tstr))  # max 4102
        #
        # assert size < 4151, "data size must be smaller than 4KB"

        resp = self.cl.update_function_configuration(
            FunctionName=func_name, Environment={"Variables": env_vars}
        )
        return resp
