# Copyright 2022 The Pigweed Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
"""Yaml config file loader mixin."""

import os
import logging
from pathlib import Path
from typing import Any, Dict, Optional, Union

import yaml

_LOG = logging.getLogger(__package__)


class MissingConfigTitle(Exception):
    """Exception for when an existing YAML file is missing config_title."""


class YamlConfigLoaderMixin:
    """Yaml Config file loader mixin.

    Use this mixin to load yaml file settings and save them into
    ``self._config``. For example:

    ::

       class ConsolePrefs(YamlConfigLoaderMixin):
           def __init__(
               self.config_init(
                   config_section_title='pw_console',
                   project_file=Path('project_file.yaml'),
                   project_user_file=Path('project_user_file.yaml'),
                   user_file=Path('~/user_file.yaml'),
                   default_config={},
                   environment_var='PW_CONSOLE_CONFIG_FILE',
               )

    """
    def config_init(
        self,
        config_section_title: str,
        project_file: Union[Path, bool] = None,
        project_user_file: Union[Path, bool] = None,
        user_file: Union[Path, bool] = None,
        default_config: Optional[Dict[Any, Any]] = None,
        environment_var: Optional[str] = None,
    ) -> None:
        """Call this to load YAML config files in order of precedence.

        The following files are loaded in this order:
        1. project_file
        2. project_user_file
        3. user_file

        Lastly, if a valid file path is specified at
        ``os.environ[environment_var]`` then load that file overriding all
        config options.

        Args:
            config_section_title: String name of this config section. For
                example: ``pw_console`` or ``pw_watch``. In the YAML file this
                is represented by a ``config_title`` key.

                ::

                   ---
                   config_title: pw_console

            project_file: Project level config file. This is intended to be a
                file living somewhere under a project folder and is checked into
                the repo. It serves as a base config all developers can inherit
                from.
            project_user_file: User's personal config file for a specific
                project. This can be a file that lives in a project folder that
                is git-ignored and not checked into the repo.
            user_file: A global user based config file. This is typically a file
                in the users home directory and settings here apply to all
                projects.
            default_config: A Python dict representing the base default
                config. This dict will be applied as a starting point before
                loading any yaml files.
            environment_var: The name of an environment variable to check for a
                config file. If a config file exists there it will be loaded on
                top of the default_config ignoring project and user files.
        """

        self._config_section_title: str = config_section_title
        self.default_config = default_config if default_config else {}
        self.reset_config()

        if project_file and isinstance(project_file, Path):
            self.project_file = Path(
                os.path.expandvars(str(project_file.expanduser())))
            self.load_config_file(self.project_file)

        if project_user_file and isinstance(project_user_file, Path):
            self.project_user_file = Path(
                os.path.expandvars(str(project_user_file.expanduser())))
            self.load_config_file(self.project_user_file)

        if user_file and isinstance(user_file, Path):
            self.user_file = Path(
                os.path.expandvars(str(user_file.expanduser())))
            self.load_config_file(self.user_file)

        # Check for a config file specified by an environment variable.
        if environment_var is None:
            return
        environment_config = os.environ.get(environment_var, None)
        if environment_config:
            env_file_path = Path(environment_config)
            if not env_file_path.is_file():
                raise FileNotFoundError(
                    f'Cannot load config file: {env_file_path}')
            self.reset_config()
            self.load_config_file(env_file_path)

    def _update_config(self, cfg: Dict[Any, Any]) -> None:
        if cfg is None:
            cfg = {}
        self._config.update(cfg)

    def reset_config(self) -> None:
        self._config: Dict[Any, Any] = {}
        self._update_config(self.default_config)

    def load_config_file(self, file_path: Path) -> None:
        if not file_path.is_file():
            return

        cfgs = yaml.safe_load_all(file_path.read_text())

        for cfg in cfgs:
            if self._config_section_title in cfg:
                self._update_config(cfg[self._config_section_title])

            elif cfg.get('config_title', False) == self._config_section_title:
                self._update_config(cfg)
            else:
                raise MissingConfigTitle(
                    '\n\nThe YAML config file "{}" is missing the expected '
                    '"config_title: {}" setting.'.format(
                        str(file_path), self._config_section_title))
