from __future__ import annotations

from structlog.dev import ConsoleRenderer
from structlog.processors import JSONRenderer
from structlog.stdlib import ProcessorFormatter
from structlog.types import EventDict
import structlog

from core.logging.filters import build_sensitive_data_processor


def ensure_message_key(
    _logger: object, _method_name: str, event_dict: EventDict
) -> EventDict:
    if "message" in event_dict:
        return event_dict
    if "event" not in event_dict:
        return event_dict

    without_event = {key: value for key, value in event_dict.items() if key != "event"}
    return {**without_event, "message": event_dict["event"]}


def build_processor_formatter(
    sensitive_fields: list[str] | None = None,
) -> ProcessorFormatter:
    redact = build_sensitive_data_processor(sensitive_fields or [])
    return ProcessorFormatter(
        foreign_pre_chain=[
            structlog.contextvars.merge_contextvars,
            structlog.processors.add_log_level,
            structlog.processors.TimeStamper(fmt="iso", utc=True),
            structlog.processors.CallsiteParameterAdder(
                parameters=[
                    structlog.processors.CallsiteParameter.MODULE,
                    structlog.processors.CallsiteParameter.FUNC_NAME,
                    structlog.processors.CallsiteParameter.LINENO,
                ]
            ),
            structlog.stdlib.ExtraAdder(),
            ensure_message_key,
        ],
        processors=[
            redact,
            ensure_message_key,
            ProcessorFormatter.remove_processors_meta,
            structlog.processors.format_exc_info,
            structlog.processors.UnicodeDecoder(),
            JSONRenderer(sort_keys=True),
        ],
    )


def build_plain_formatter(
    sensitive_fields: list[str] | None = None,
) -> ProcessorFormatter:
    redact = build_sensitive_data_processor(sensitive_fields or [])
    return ProcessorFormatter(
        foreign_pre_chain=[
            structlog.contextvars.merge_contextvars,
            structlog.processors.add_log_level,
            structlog.processors.TimeStamper(fmt="iso", utc=True),
            structlog.processors.CallsiteParameterAdder(
                parameters=[
                    structlog.processors.CallsiteParameter.MODULE,
                    structlog.processors.CallsiteParameter.FUNC_NAME,
                    structlog.processors.CallsiteParameter.LINENO,
                ]
            ),
            structlog.stdlib.ExtraAdder(),
            ensure_message_key,
        ],
        processors=[
            redact,
            ensure_message_key,
            ProcessorFormatter.remove_processors_meta,
            structlog.processors.format_exc_info,
            structlog.processors.UnicodeDecoder(),
            ConsoleRenderer(colors=False),
        ],
    )
