import os
import logging
import requests
from dotenv import dotenv_values  # , load_dotenv
import yaml
# #------- ConfigBase
from .settings_utils import ConfigBase
from .settings_utils import (
    RunnerType,
)
# from typing import Literal
from pathlib import Path
from .settings_config import ConfigV2
from pydantic import (
    ValidationError,
)

logger = logging.getLogger(__name__)

# config = None


DEFAULT_BASE_DIR = os.getcwd()
# DEFAULT_SOURCE_MAPPING_FILEPATH = str(Path(DEFAULT_BASE_DIR) /
#                                       'field_mapping.csv')
DEFAULT_RUNNER_TYPE = RunnerType.hris


# #------------------ V2 Configuration

VERSION_TO_CONFIG = {
    'v1': ConfigBase,
    'v2': ConfigV2
}


class Config:
    # _CONFIG: Optional[ConfigBase] = None
    _CONFIG = None
    BASE_DIR = DEFAULT_BASE_DIR

    def __init__(self, config_file=None, **kwargs):

        # Use singleton pattern to store config file location/load config
        # once. Also make a global config object available across the module
        self.update(config_file=config_file)

    @staticmethod
    def reset():
        # Config._CONFIG = None
        Config.update()

    @staticmethod
    def update(config_file=None,
               config_version='v2',
               config_url=None,
               config_content=None,
               reset=True,
               **kwargs):

        config_format = None

        config_dict = {
            'LOG_LEVEL': 'INFO',
            'OAA_TIME_ZONE': 'Z',
            'RUNNER_TYPE': kwargs.get('runner_type', DEFAULT_RUNNER_TYPE),
            # load shared development variables
            **dotenv_values(Path(os.getcwd()) / ".env"),
        }

        if reset:
            Config._CONFIG = None

        elif Config._CONFIG:
            config_dict.update(Config._CONFIG.model_dump())

        base_config = ConfigBase.model_validate(config_dict,
                                                context={
                                                    'pre-config': True
                                                })
        # config_dict.update()

        if config_file:
            config_format = os.path.splitext(config_file)

            logger.debug('config_file: %s', config_file)
            logger.debug('config_format: %s', config_format)
        # We may want to be able to reset the config completely

        if os.getenv('DOTENV_FILE'):
            config_dict.update(dotenv_values(os.environ['DOTENV_FILE']))

        if config_url:
            yaml_text = requests.get(config_url).text
            content_yaml = yaml.safe_load(yaml_text)
            config_dict.update(content_yaml)
            base_config = VERSION_TO_CONFIG.get(config_version,
                                                ConfigBase)

        if config_content:
            content_yaml = yaml.safe_load(config_content)
            config_version = content_yaml.get('version', config_version)
            config_dict.update(content_yaml)

        # Validate the base configuration which only contains a few
        # core configuration options

        config_dict.update(os.environ)

        if kwargs:
            config_dict.update(kwargs)

        if config_file:
            # config_file = make_abs(config_file, base_config.base_dir)
            # config_dict['BASE_DIR'] = os.path.dirname(config_file)

            if not os.path.exists(config_file):
                # import bpdb; bpdb.set_trace()  # noqa: E702
                logger.error('config_file passed in does not exist %s',
                             config_file)
            else:

                Config.BASE_DIR = os.path.dirname(Path(config_file).absolute())
                new_values = yaml.safe_load(open(config_file))

                config_version = new_values.get('version', config_version)
                config_dict.update(new_values)
                config_dict['config_file'] = config_file

                base_config = VERSION_TO_CONFIG.get(config_version,
                                                    ConfigBase)

        try:
            # import bpdb; bpdb.set_trace()  # noqa: E702
            # base_dir = getattr(base_config,
            #                    'base_dir',
            #                    DEFAULT_BASE_DIR)
            loaded_config = base_config.model_validate(config_dict, context={})

            Config._CONFIG = loaded_config
        except ValidationError as err:
            # from pprint import pprint
            # pprint(config_dict)

            for e in err.errors():
                err_str = f"--- {'.'.join(e['loc'])}: {e['type']}: {e['msg']}"
                err_str = str(e)
                logger.error(err_str)
                print(err_str)
            Config._CONFIG = None

    @staticmethod
    def get(key):

        if Config._CONFIG:
            # return getattr(Config._CONFIG, key.lower())

            return getattr(Config._CONFIG, key)

    def __getattr__(self, key):

        if Config._CONFIG:
            return getattr(Config._CONFIG, key,
                           getattr(Config._CONFIG, key.lower(), None))

    @staticmethod
    def valid():
        return bool(Config._CONFIG)


def load_config(config_file):
    return Config(config_file=config_file)


config = Config(config_file=None)
