#  SPDX-License-Identifier: MPL-2.0
#    Copyright (c) 2022 Philipp Le <philipp@philipple.de>.
#  This Source Code Form is subject to the terms of the Mozilla Public
#  License, v. 2.0. If a copy of the MPL was not distributed with this
#  file, You can obtain one at https://mozilla.org/MPL/2.0/.

from __future__ import annotations

import toml
import json
from typing import Dict, AnyStr, Callable, Type, Any, Optional
from pydantic import BaseModel, PrivateAttr
import appdirs
import os
import logging


class ConfigObject(BaseModel):
    _KEY: AnyStr = PrivateAttr()

    @classmethod
    def get_key(cls) -> AnyStr:
        return cls._KEY


class Store:
    __instances: Dict[str, Store] = {}

    def __init__(self, raw_objs: Dict[AnyStr, Any], save_cb: Optional[Callable[[Store], None]] = None):
        self._raw_objs: Dict[AnyStr, Any] = raw_objs
        self._cfg_objs: Dict[AnyStr, ConfigObject] = {}
        self._save_cb: Optional[Callable[[Store], None]] = save_cb

    @staticmethod
    def get_instance(name: str = 'default') -> Store:
        if name in Store.__instances:
            return Store.__instances[name]
        else:
            raise KeyError(f'The Store instance {name} does not exist.')

    @classmethod
    def load_obj(cls, obj: Dict[AnyStr, Any], name: str = 'default', *args, **kwargs) -> Store:
        if name not in Store.__instances:
            Store.__instances[name] = cls(obj, *args, **kwargs)
            return Store.__instances[name]
        else:
            raise KeyError(f'The Store instance {name} already exists.')

    @classmethod
    def new(cls, name: str = 'default', *args, **kwargs) -> Store:
        if name not in Store.__instances:
            Store.__instances[name] = cls({}, *args, **kwargs)
            return Store.__instances[name]
        else:
            raise KeyError(f'The Store instance {name} already exists.')

    def dump_obj(self) -> Dict[AnyStr, Any]:
        obj: Dict[AnyStr, Any] = self._raw_objs
        for key, item in self._cfg_objs.items():
            obj[key] = json.loads(item.json())
        return obj

    def get_config(self, tp: Type[ConfigObject]):
        key = tp.get_key()
        if key not in self._cfg_objs:
            if key in self._raw_objs:
                self._cfg_objs[key] = tp.parse_obj(self._raw_objs[key])
            else:
                self._cfg_objs[key] = tp()
        return self._cfg_objs[key]

    def save(self) -> None:
        if self._save_cb is not None:
            self._save_cb(self)


class TomlStore(Store):
    def __init__(self, raw_objs: Dict[AnyStr, Any], toml_file: str):
        super().__init__(raw_objs, save_cb=self._do_save)
        self.toml_file: str = toml_file

    @classmethod
    def load_or_create_toml(cls, toml_file: str, name: str = 'default') -> TomlStore:
        try:
            s = Store.get_instance(name)
        except KeyError:
            try:
                s = TomlStore.load_toml(toml_file, name)
                logging.info(f'Loaded config from {toml_file}')
            except FileNotFoundError:
                s = TomlStore.new(name, toml_file=toml_file)
                logging.info(f'New config at {toml_file}')
        return s

    @classmethod
    def load_toml(cls, toml_file: str, name: str = 'default') -> TomlStore:
        obj = toml.load(toml_file)
        return TomlStore.load_obj(obj, name, toml_file=toml_file)

    def dump_toml(self) -> None:
        base_dir = os.path.dirname(self.toml_file)
        if not os.path.exists(base_dir):
            logging.info(f'Creating directory {base_dir}')
            os.mkdir(base_dir)
        with open(self.toml_file, 'w', encoding='utf-8') as f:
            toml.dump(self.dump_obj(), f)

    def _do_save(self, s: Store) -> None:
        assert id(self) == id(s)
        self.dump_toml()


DEFAULT_PATH = os.path.join(
    appdirs.user_config_dir('dcs_interactive', 'Philipp Le'),
    'config.toml'
)


def default_store() -> TomlStore:
    return TomlStore.load_or_create_toml(DEFAULT_PATH, 'default')

