import os
import json
import logging
import opencryptobot.constants as con

from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler


class ConfigManager:

    _CFG_FILE = con.CFG_FILE

    _cfg = dict()

    ignore = False

    def __init__(self, config_file=None):
        if config_file:
            ConfigManager._CFG_FILE = config_file

        ConfigManager._watch_changes()

    # Watch for config file changes
    @staticmethod
    def _watch_changes():
        observer = Observer()

        file = ConfigManager._CFG_FILE
        method = ConfigManager._read_cfg
        change_handler = ChangeHandler(file, method)

        observer.schedule(change_handler, ".", recursive=True)
        observer.start()

    @staticmethod
    def _read_cfg():
        if os.path.isfile(ConfigManager._CFG_FILE):
            with open(ConfigManager._CFG_FILE) as config_file:
                ConfigManager._cfg = json.load(config_file)
        else:
            cfg_file = ConfigManager._CFG_FILE
            exit(f"ERROR: No configuration file '{cfg_file}' found")

    @staticmethod
    def _write_cfg():
        if os.path.isfile(ConfigManager._CFG_FILE):
            with open(ConfigManager._CFG_FILE, "w") as config_file:
                json.dump(ConfigManager._cfg, config_file, indent=4)
        else:
            cfg_file = ConfigManager._CFG_FILE
            exit(f"ERROR: No configuration file '{cfg_file}' found")

    @staticmethod
    def get(*keys):
        if not ConfigManager._cfg:
            ConfigManager._read_cfg()

        value = ConfigManager._cfg
        for key in keys:
            try:
                value = value[key]
            except KeyError as e:
                err = f"Couldn't read '{key}' from Config"
                logging.debug(f"{repr(e)} - {err}")
                return None

        return value if value is not None else None

    @staticmethod
    def set(value, *keys):
        tmp_cfg = ConfigManager._cfg

        for key in keys[:-1]:
            tmp_cfg = tmp_cfg.setdefault(key, {})

        tmp_cfg[keys[-1]] = value

        ConfigManager.ignore = True
        ConfigManager._write_cfg()

    @staticmethod
    def remove(*keys):
        for key in keys:
            if key in ConfigManager._cfg:
                del ConfigManager._cfg[key]
                ConfigManager._write_cfg()


class ChangeHandler(FileSystemEventHandler):
    file = None
    method = None
    old = 0

    def __init__(self, file, method):
        type(self).file = file
        type(self).method = method

    @staticmethod
    def on_modified(event):
        cfg_path = os.path.join('.', con.CFG_DIR, con.CFG_FILE)

        if event.src_path == cfg_path:
            statbuf = os.stat(event.src_path)
            new = statbuf.st_mtime

            # Workaround for watchdog bug
            # https://github.com/gorakhargosh/watchdog/issues/93
            if (new - ChangeHandler.old) > 0.5:
                if ConfigManager.ignore:
                    ConfigManager.ignore = False
                else:
                    ChangeHandler.method()

            ChangeHandler.old = new