import os
import logging

from ylog.context import get_log_context


class LoggingSecretError(Exception):
    pass


class TraceLogger(object):
    current_logger = None

    def __init__(self, current_logger):
        self.current_logger = current_logger

    def __getattr__(self, item):
        if item == '__wrapped__':
            raise AttributeError
        return self.current_logger.exception


class DomenatorLogger(logging.Logger):
    def makeRecord(self, name, level, fn, lno, msg, args, exc_info, func=None, extra=None, sinfo=None):
        if extra is None:
            extra = {}
        context = get_log_context()

        extra['host_name'] = os.environ.get('DEPLOY_POD_PERSISTENT_FQDN', 'localhost')
        extra['appname'] = '%s-%s' % (
            os.environ.get('DEPLOY_STAGE_ID', ''),
            os.environ.get('DEPLOY_UNIT_ID', '').replace('_standalone', '')
        )
        extra['ycrid'] = context.get('ycrid', '')
        extra['request_id'] = context.get('request_id', '')

        return super(DomenatorLogger, self).makeRecord(name, level, fn, lno, msg, args, exc_info, func, extra, sinfo)


class TSKVFormatter(logging.Formatter):
    _special_substitutions = [
        ('\\', '\\\\'),
        ('\t', r'\t'),
        ('\r', r'\r'),
        ('\n', r'\n'),
        ('\0', r'\0'),
    ]

    def format(self, record: logging.LogRecord) -> str:
        if self.usesTime():
            record.asctime = self.formatTime(record, self.datefmt)

        record.message = record.getMessage()
        if not hasattr(record, 'context'):
            record.context = {}

        if record.exc_info:
            # Кэшируем трейс, т.к. он сохраняется между логгерами.
            if not record.exc_text:
                record.exc_text = self.formatException(record.exc_info)
        if record.exc_text:
            if record.message[-1:] != r"\n":
                record.message += r"\n"
            record.message = record.message + record.exc_text
        return self._fmt % self.escape(record.__dict__)

    def escape(self, data):
        if isinstance(data, str):
            for search, replacement in self._special_substitutions:
                data = data.replace(search, replacement)
        elif isinstance(data, dict):
            new_data = {}
            for key, value in data.items():
                new_data[key] = self.escape(value)
            data = new_data
        elif isinstance(data, (list, tuple)):
            new_data = []
            for value in data:
                new_data.append(self.escape(value))
            if isinstance(data, tuple):
                data = tuple(new_data)
            else:
                data = new_data
        return data


def get_logger(log_name='dom_access'):
    logging.setLoggerClass(DomenatorLogger)
    log = logging.getLogger(log_name)
    return log
