import os
from typing import Optional


class ConfigValueNotSet(Exception):
    pass


class Config:
    def __init__(self, options_map: dict = None):
        self.options_map = options_map

    def init(self, dotenv_path: Optional[str] = None):
        load_dotenv(dotenv_path)

        for option in self.options_map:
            value = self._load_value(option)
            setattr(self, option, value)

    def _load_value(self, option: str):
        params = self.options_map[option]
        value = os.getenv(option)

        if value is not None:
            converter = params.get("converter", lambda v: v)
            return converter(value)

        if "default" in params:
            return params["default"]

        raise ConfigValueNotSet(option)

    def __getitem__(self, item):
        return getattr(self, item)

    def get(self, item):
        try:
            return self[item]
        except AttributeError:
            return None


def load_dotenv(fpath: str):
    fpath = fpath or os.path.join(os.getcwd(), ".env")
    if not os.path.isfile(fpath):
        return

    with open(fpath, "r") as f:
        for line in f.readlines():
            line = line.strip()

            if not line or line.startswith("#"):
                continue

            key, value = line.split("=", 1)
            if key not in os.environ:
                os.environ[key] = value
