from __future__ import annotations

import logging
import re
from collections.abc import Callable
from typing import cast

from structlog.types import EventDict


_NORMALIZE_PATTERN = re.compile(r"[^a-z0-9]")


def _normalize_key(value: str) -> str:
    return _NORMALIZE_PATTERN.sub("", value.lower())


def _is_sensitive_key(key: object, sensitive_fields: set[str]) -> bool:
    normalized_key = _normalize_key(str(key))
    return normalized_key in sensitive_fields or any(
        fragment in normalized_key for fragment in sensitive_fields
    )


def _redact_value(value: object, sensitive_fields: set[str]) -> object:
    if isinstance(value, dict):
        typed_value = cast(dict[str, object], value)
        return {
            key: (
                "[REDACTED]"
                if _is_sensitive_key(key, sensitive_fields)
                else _redact_value(inner, sensitive_fields)
            )
            for key, inner in typed_value.items()
        }
    if isinstance(value, list):
        return [_redact_value(item, sensitive_fields) for item in value]
    return value


def build_sensitive_data_processor(
    sensitive_fields: list[str],
) -> Callable[[object, str, EventDict], EventDict]:
    normalized = {_normalize_key(field) for field in sensitive_fields}

    def processor(
        _logger: object, _method_name: str, event_dict: EventDict
    ) -> EventDict:
        return cast(EventDict, _redact_value(event_dict, normalized))

    return processor


class ErrorLevelFilter(logging.Filter):
    def filter(self, record: logging.LogRecord) -> bool:
        return record.levelno >= logging.ERROR
