import logging
import threading
import os
from threading import Lock


class EdpLogTypeFilter(object):
    def __init__(self, log_source, **kwargs):
        self.inner_filters = [
            LogLevelNameFilter(),
            ThreadIdFilter(),
            CountFilter(),
            MessageProcessorThreadNameFilter(),
            FixedInfoFilter(log_source=log_source, log_type="edp-log-type-gelf", log_verion="1.0", **kwargs),
            EnvironmentVariableLogFilter(),
            ContextLogFilter()
        ]

    def filter(self, record):
        for inner_filter in self.inner_filters:
            inner_filter.filter(record)
        return 1


class LogLevelNameFilter(object):
    def filter(self, record):
        record.log_level = logging.getLevelName(record.levelno)


class ThreadIdFilter(object):
    def filter(self, record):
        record.thread_id = record.thread
        return 1


class CountFilter(object):
    def __init__(self):
        self.lock = Lock()
        self.count = 0
        self.max_count = 99

    def get_count(self):
        with self.lock:
            self.count += 1
            if self.count > self.max_count:
                self.count = 1
            return self.count

    def filter(self, record):
        record.count = self.get_count()
        return 1


class FixedInfoFilter(object):
    def __init__(self, **fields):
        self.fields = {}
        for field_name in fields.keys():
            field_value = fields[field_name]
            if not isinstance(field_name, str):
                raise Exception("The field´s name must be a str")
            self.fields[field_name] = field_value

    def filter(self, record):
        for field in self.fields:
            setattr(record, field, self.fields[field])
        return 1


class MessageProcessorThreadNameFilter(object):
    def filter(self, record):
        try:
            if record.threadName is not None and record.threadName.startswith("MessageProcessorThread"):
                first_index = record.threadName.index("$")
                last_index = record.threadName.rindex("$")
                if first_index == last_index:
                    return 1
                thread_name = record.threadName[:first_index]
                request_id = record.threadName[last_index + 1:]
                processor_name = record.threadName[first_index + 1:last_index]
                record.threadName = thread_name
                record.request_id = request_id
                record.processor_name = processor_name
                if processor_name.startswith("HttpMessageProcessor") and processor_name != "HttpMessageProcessor":
                    first_index = processor_name.index("$")
                    last_index = processor_name.rindex("$")
                    url = processor_name[last_index + 1:]
                    method = processor_name[first_index + 1:last_index]
                    record.url = url
                    record.http_method = method
                    record.processor_name = "HttpMessageProcessor"
            return 1
        except Exception as ex:
            record.error_processing_thread_name = str(ex)


class EnvironmentVariableLogFilter(FixedInfoFilter):
    def __init__(self):
        field_name_pattern = "GRAYLOG_FIELD_"
        pattern_length = len(field_name_pattern)
        fields = {}
        for var in os.environ.keys():
            if var.startswith(field_name_pattern):
                field_name = var[pattern_length:].lower()
                field_value = os.environ[var]
                fields[field_name] = field_value

        super(EnvironmentVariableLogFilter, self).__init__(**fields)


class ContextLogFilter(object):
    def filter(self, record):
        current_thread = threading.current_thread()
        if hasattr(current_thread, "_edp_context_name"):
            record.context_name = threading.current_thread()._edp_context_name
