import os
import sys
import logging
import logging.handlers

_EXTENDED_LOGS = os.getenv("LOG_EXTENDED", "true").lower() == "true"
_LOG_DATE = os.getenv("LOG_DATE", "false").lower() == "true"
_LOG_DATE_FORMAT = os.getenv("LOG_DATE_FORMAT", "%Y-%m-%dT%H:%M:%S%z")

# disable root logger
root_logger = logging.getLogger()
root_logger.disabled = True

# Parent logger
parent_logger = logging.getLogger("hestia_earth")


def _get_level():
    return logging.getLevelName(os.getenv("LOG_LEVEL", "INFO"))


parent_logger.setLevel(_get_level())

formatter = (
    (
        logging.Formatter(
            '{"timestamp": "%(asctime)s", "level": "%(levelname)s", "logger": "%(name)s", "message": "%(message)s"}',
            _LOG_DATE_FORMAT,
        )
        if _LOG_DATE
        else logging.Formatter(
            '{"level": "%(levelname)s", "logger": "%(name)s", "message": "%(message)s"}'
        )
    )
    if _EXTENDED_LOGS
    else logging.Formatter(
        '{"logger": "%(name)s", "message": "%(message)s"}', _LOG_DATE_FORMAT
    )
)


def disable_stdout_logging():
    """
    Disable deffault logging to stdout.
    """
    parent_logger.propagate = False

    for handler in parent_logger.handlers[:]:
        parent_logger.removeHandler(handler)

    parent_logger.root.handlers = [logging.NullHandler()]
    parent_logger.removeHandler(sys.stdout)
    parent_logger.setLevel(_get_level())


def flush_logs(logger: logging.Logger):
    """
    Force all handlers to write their buffers to disk.
    """
    for handler in logger.handlers:
        handler.flush()


def log_to_file(
    filepath: str,
    buffer_logs_in_memory: bool = False,
    memory_handler_capacity: int = 10000,
):
    """
    By default, all logs are saved into a file with path stored in the env variable `LOG_FILENAME`.
    If you do not set the environment variable `LOG_FILENAME`, you can use this function with the file path.

    Parameters
    ----------
    filepath : str
        Path of the file.
    buffer_logs_in_memory : bool
        Buffer the logs in memory before writing to the file.
    memory_handler_capacity : int
        When using `buffer_logs_in_memory`, this can be set to throttle the writing by number of lines written.
    """
    file_handler = logging.FileHandler(filepath, encoding="utf-8")
    file_handler.setFormatter(formatter)

    handler = (
        logging.handlers.MemoryHandler(
            capacity=memory_handler_capacity, target=file_handler
        )
        if buffer_logs_in_memory
        else file_handler
    )

    handler.setLevel(_get_level())
    parent_logger.addHandler(handler)


def log_to_stream():
    """
    Log to IO stream instead of a file. Make sure not to set env variable `LOG_FILENAME` so the stream can be used.
    """
    import io

    log_stream = io.StringIO()
    handler = logging.StreamHandler(log_stream)
    handler.setFormatter(formatter)
    handler.setLevel(_get_level())
    parent_logger.addHandler(handler)
    return log_stream


LOG_FILENAME = os.getenv("LOG_FILENAME")
if LOG_FILENAME is not None:
    log_to_file(LOG_FILENAME)


def get_logger(name: str):
    logger = logging.getLogger(name)
    logger.setLevel(_get_level())
    return logger


def log_join_args(**kwargs):
    return ", ".join([f"{key}={value}" for key, value in kwargs.items()])


def log_node_suffix(node: dict = {}):
    node_type = node.get("@type", node.get("type")) if node else None
    node_id = (
        node.get("@id", node.get("id", node.get("term", {}).get("@id")))
        if node
        else None
    )
    return f"{node_type.lower()}={node_id}, " if node_type else ""
