from __future__ import annotations

import copy
import logging

from clarabot_nano_common.utility.handlers import AbstractHandler

from clarabot_nano.core.config.schema import REMOTE_CONFIG_SCHEMA

NANO_INFO_LOGGER = logging.getLogger("nano/info")


class RemoteConfigUpdateError(Exception):
    def __init__(self, info: str):
        Exception.__init__(self, info)

    @property
    def info(self) -> str:
        return self.args[0]


class AbstractRemoteConfigUpdateHandler(AbstractHandler):
    def __init__(self, default_config: dict, config: dict, local_config: dict):
        self._default_config = default_config
        self._original_config = copy.deepcopy(config)
        self._c = config
        # some handler require access to this for policy enforcement
        self._local_c = local_config

    def validate(self):
        c = copy.deepcopy(self._default_config)
        c.update(self._c)
        REMOTE_CONFIG_SCHEMA.validate(c)

    def execute(self, data: dict, source: str):
        self.validate()
        self._execute(data)
        self.validate()
        # Note: this logging is for debug/info only. If this request has come through the gateway from remote then
        # the request has already been written to the access-log with user information.
        NANO_INFO_LOGGER.info(
            f"Config change: {self._describe_change(self._original_config, self._c, data)} by request from {source}"
        )

    def _execute(self, data: dict):
        raise NotImplementedError()

    def _describe_change(self, old_config: dict, new_config: dict, data: dict) -> str:
        raise NotImplementedError()
