import threading

from grayloghelper import (
    ContextLogFilter,
    CountFilter,
    EnvironmentVariableLogFilter,
    FixedInfoFilter,
    MessageProcessorThreadNameFilter,
)


class TestCountFilter:
    def test_increments_per_record(self, make_record):
        f = CountFilter()
        r1, r2, r3 = make_record(), make_record(), make_record()
        f.filter(r1)
        f.filter(r2)
        f.filter(r3)
        assert (r1.count, r2.count, r3.count) == (1, 2, 3)

    def test_rolls_over_after_max(self, make_record):
        f = CountFilter()
        f.count = 99  # next call increments to 100, then rolls to 1
        rec = make_record()
        f.filter(rec)
        assert rec.count == 1
        rec2 = make_record()
        f.filter(rec2)
        assert rec2.count == 2


class TestMessageProcessorThreadNameFilter:
    def test_extracts_processor_and_request_id(self, make_record):
        rec = make_record(thread_name="MessageProcessorThread$OrderProcessor$req-42")
        MessageProcessorThreadNameFilter().filter(rec)
        assert rec.threadName == "MessageProcessorThread"
        assert rec.processor_name == "OrderProcessor"
        assert rec.request_id == "req-42"

    def test_ignores_non_message_processor_threads(self, make_record):
        rec = make_record(thread_name="MainThread")
        MessageProcessorThreadNameFilter().filter(rec)
        assert rec.threadName == "MainThread"
        assert not hasattr(rec, "processor_name")
        assert not hasattr(rec, "request_id")

    def test_malformed_thread_name_records_error(self, make_record):
        rec = make_record(thread_name="MessageProcessorThread_no_dollar_signs")
        MessageProcessorThreadNameFilter().filter(rec)
        assert hasattr(rec, "error_processing_thread_name")
        assert "MessageProcessorThread_no_dollar_signs" in rec.error_processing_thread_name


class TestFixedInfoFilter:
    def test_applies_all_fields(self, make_record):
        rec = make_record()
        FixedInfoFilter(foo="bar", region="br").filter(rec)
        assert rec.foo == "bar"
        assert rec.region == "br"


class TestEnvironmentVariableLogFilter:
    def test_picks_up_prefixed_env_vars(self, make_record, monkeypatch):
        monkeypatch.setenv("GRAYLOG_FIELD_REGION", "br-sp")
        monkeypatch.setenv("GRAYLOG_FIELD_CLUSTER", "edge-1")
        monkeypatch.setenv("UNRELATED", "ignored")

        rec = make_record()
        EnvironmentVariableLogFilter().filter(rec)

        assert rec.region == "br-sp"
        assert rec.cluster == "edge-1"
        assert not hasattr(rec, "unrelated")

    def test_lowercases_field_names(self, make_record, monkeypatch):
        monkeypatch.setenv("GRAYLOG_FIELD_CamelCase", "v")
        rec = make_record()
        EnvironmentVariableLogFilter().filter(rec)
        assert rec.camelcase == "v"


class TestContextLogFilter:
    def test_copies_context_name(self, make_record):
        threading.current_thread()._edp_context_name = "tenant-A"
        rec = make_record()
        ContextLogFilter().filter(rec)
        assert rec.context_name == "tenant-A"

    def test_no_op_when_attribute_missing(self, make_record):
        rec = make_record()
        ContextLogFilter().filter(rec)
        assert not hasattr(rec, "context_name")
