"""Security utilities — secret redaction, input sanitization."""

from __future__ import annotations

import re
from typing import Any

# Patterns that look like secrets/API keys
_SECRET_PATTERNS: list[re.Pattern[str]] = [
    re.compile(r"(sk-[a-zA-Z0-9]{20,})"),  # OpenAI/Anthropic keys
    re.compile(r"(tvly-[a-zA-Z0-9]{20,})"),  # Tavily keys
    re.compile(r"(BSA[a-zA-Z0-9]{20,})"),  # Brave Search keys
    re.compile(r"(key-[a-zA-Z0-9]{20,})"),  # Generic API keys
    re.compile(r"(?i)(api[_-]?key\s*[=:]\s*)([^\s,;\"']+)"),  # key=value patterns
    re.compile(r"(?i)(password\s*[=:]\s*)([^\s,;\"']+)"),  # password=value
    re.compile(r"(?i)(secret\s*[=:]\s*)([^\s,;\"']+)"),  # secret=value
    re.compile(r"(?i)(token\s*[=:]\s*)([^\s,;\"']+)"),  # token=value
]

# Keys in dicts that should be redacted
_SENSITIVE_KEYS = frozenset(
    {
        "api_key",
        "apikey",
        "api_secret",
        "password",
        "secret",
        "token",
        "access_token",
        "refresh_token",
        "private_key",
        "tavily_api_key",
        "serpapi_api_key",
        "brave_api_key",
    }
)


def redact_secrets(text: str) -> str:
    """Replace potential secrets in a string with [REDACTED]."""
    result = text
    for pattern in _SECRET_PATTERNS:
        result = pattern.sub(lambda m: m.group(0)[:4] + "[REDACTED]", result)
    return result


def redact_dict(data: dict[str, Any], depth: int = 0) -> dict[str, Any]:
    """Recursively redact sensitive keys in a dictionary.

    Returns a new dict with sensitive values replaced.
    """
    if depth > 10:
        return data

    result: dict[str, Any] = {}
    for key, value in data.items():
        if key.lower() in _SENSITIVE_KEYS and isinstance(value, str) and value:
            result[key] = value[:4] + "***" if len(value) > 4 else "***"
        elif isinstance(value, dict):
            result[key] = redact_dict(value, depth + 1)
        elif isinstance(value, list):
            result[key] = [
                redact_dict(item, depth + 1) if isinstance(item, dict) else item for item in value
            ]
        else:
            result[key] = value
    return result


def sanitize_log_message(message: str) -> str:
    """Sanitize a message for safe logging — redact secrets."""
    return redact_secrets(message)
