"""Module for configuring logger."""

import datetime as dt
import logging
import os
import platform
from logging.handlers import RotatingFileHandler
from pathlib import Path

_LOGGER_CONFIGURED: dict = {}
_DEFAULT_NAMESPACE = 'x1'
# to share between different namespaces
_FILE_LOGGER = None
_ENV_LOGGING_TO_FILE = 'X1_LOGGING_TO_FILE'
_ENV_LOGGING_LEVEL = 'X1_LOGGING_LEVEL'


def _get_root_dir():
    # be careful when moving this function or file
    return Path(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))


def _create_logger(namespace: str, job_id: str, logfile_name: str) -> logging.Logger:
    """
    Create and configure logger as infractl expects it to be.

    Parameters
    ----------
    namespace : str
        Logging namespace to use, e.g. `_DEFAULT_NAMESPACE`.
    job_id : str
        Part of path to where logs are stored.
    logfile_name : str
        Name of the log file to create.

    Returns
    -------
    Logger
    """
    logger = logging.getLogger(namespace)
    logger.setLevel(logging.DEBUG)

    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

    x1_logging_to_file = os.environ.get(_ENV_LOGGING_TO_FILE, None)
    if x1_logging_to_file not in ('TRUE', 'true', None):
        raise ValueError(
            f'env var: {_ENV_LOGGING_TO_FILE}={x1_logging_to_file}, '
            f'allowed values: {("TRUE", "true")}'
        )
    if x1_logging_to_file:
        global _FILE_LOGGER
        if _FILE_LOGGER is None:
            # Pathlib makes it OS agnostic.
            log_path = _get_root_dir() / 'logs'
            log_path.mkdir(exist_ok=True)

            # Add gitignore to the log directory.
            ignore_log_path = log_path / '.gitignore'
            if not ignore_log_path.exists():
                ignore_log_path.write_text('# Automatically generated by infractl.\n*\n')

            log_dir = log_path / f'job_{job_id}'
            log_dir.mkdir(parents=True, exist_ok=True)
            log_filename = log_dir / f'{logfile_name}.log'

            file_handler = RotatingFileHandler(
                filename=log_filename,
                mode='a',
                backupCount=10,
            )
            file_handler.setFormatter(formatter)
            file_handler.setLevel(logging.INFO)
            _FILE_LOGGER = file_handler
        else:
            file_handler = _FILE_LOGGER
        logger.addHandler(file_handler)

    stream_handler = logging.StreamHandler()
    stream_handler.setFormatter(formatter)
    stream_handler.setLevel(os.environ.get(_ENV_LOGGING_LEVEL, 'WARNING'))
    logger.addHandler(stream_handler)

    return logger


def configure_logging(namespace) -> None:
    """Configure infractl logging by setting up directory structure and formatting."""
    current_timestamp = dt.datetime.now().strftime('%Y%m%d%H%M%S')

    root = logging.getLogger()
    # not sure why `PrefectConsoleHandler` is enabled by default as a root looger
    if len(root.handlers) == 1 and 'PrefectConsoleHandler' in str(root.handlers[0]):
        root.handlers = []

    logger = _create_logger(
        namespace,
        job_id=current_timestamp,
        logfile_name='info',
    )

    if namespace == _DEFAULT_NAMESPACE:
        logger.info('OS Version: %s', platform.platform())
        logger.info('Python Version:  %s', platform.python_version())


def get_logger(namespace: str = _DEFAULT_NAMESPACE) -> logging.Logger:
    """
    Configure infractl logger and returns the logger.

    Parameters
    ----------
    namespace : str, default: `_DEFAULT_NAMESPACE`
        Which namespace to use for logging.

    Returns
    -------
    logging.Logger
        The infractl logger.
    """
    if _LOGGER_CONFIGURED.get(namespace) is None:
        configure_logging(namespace)
        _LOGGER_CONFIGURED[namespace] = True

    return logging.getLogger(namespace)
