import json
import logging
import pathlib
import typing
from logging import config as logging_config

__dir = pathlib.Path(__file__).parent
__conf: dict[str, str] | None = None

def _load_config(path: pathlib.Path, substitutions: dict[str, str] | None = None) -> dict[str, typing.Any]:
  with open(path) as file:
    if substitutions:
      contents = file.read()
      for key, value in substitutions.items():
        # Replaces the key matches
        #
        # Example:
        #   {"key": "value"}
        #   "/path/to/${key}/file" -> "/path/to/value/file"
        contents = contents.replace(f"${{{key}}}", value)

      json_data = json.loads(contents)

    else:
      json_data = json.load(file)

  return json_data


def log_config() -> dict[str, str]:
  if __conf is None:
    raise ValueError("logger not configured, must call configured_logger first")

  return __conf


def configured_logger(
  *,
  mode: str,
  config_override: pathlib.Path | None = None,
  substitutions: dict[str, str] | None = None,
) -> logging.Logger:
  """
  Configure the logger based on the mode and return the root logger

  Args:
      mode (str): The mode to configure the logger for (production, development, testing)
      config_override (pathlib.Path, optional): A path to a custom logging config. Defaults to None.
      substitutions (dict[str, str], optional): A dictionary of substitutions to apply to the logging config.
  """
  global __conf

  if config_override:
    __conf = _load_config(config_override, substitutions)
  else:
    if mode == "production":
      __conf = _load_config(__dir / "logconf.prod.json", substitutions)
    elif mode == "development":
      __conf = _load_config(__dir / "logconf.dev.json", substitutions)
    elif mode == "testing":
      __conf = _load_config(__dir / "logconf.test.json", substitutions)
    else:
      raise ValueError(f"Invalid mode: {mode}")

  logging_config.dictConfig(config=__conf)
  return logging.getLogger()