"""Utility functions for the monitoring module.

Sanitization, serialization, and helper functions.
"""

from __future__ import annotations

import json
from typing import Any

from pydantic import BaseModel

_SENSITIVE_KEYS = frozenset(
    {
        "api_key",
        "password",
        "secret",
        "token",
        "authorization",
        "db_password",
        "api_secret",
        "access_token",
        "refresh_token",
    }
)


def sanitize_dict(
    data: dict[str, Any],
    excluded_fields: frozenset[str] | set[str] | list[str] = _SENSITIVE_KEYS,
    max_str_len: int = 10000,
) -> dict[str, Any]:
    """Sanitize a dictionary for storage — mask secrets, truncate long strings.

    Args:
        data: Dict to sanitize.
        excluded_fields: Field names whose values should be masked.
        max_str_len: Max string length before truncation.

    Returns:
        Sanitized copy of the dict.
    """
    excluded = (
        frozenset(excluded_fields)
        if not isinstance(excluded_fields, frozenset)
        else excluded_fields
    )
    sanitized: dict[str, Any] = {}

    for key, value in data.items():
        if key.lower() in excluded:
            sanitized[key] = "***"
        elif isinstance(value, str) and len(value) > max_str_len:
            sanitized[key] = (
                value[:max_str_len]
                + f"... [truncated, total {len(value)} chars]"
            )
        elif isinstance(value, dict):
            sanitized[key] = sanitize_dict(value, excluded, max_str_len)
        elif isinstance(value, list):
            sanitized[key] = [
                (
                    sanitize_dict(item, excluded, max_str_len)
                    if isinstance(item, dict)
                    else item
                )
                for item in value
            ]
        else:
            sanitized[key] = value

    return sanitized


def model_to_jsonb(model: BaseModel | None) -> dict[str, Any] | None:
    """Serialize a Pydantic model to a JSON-compatible dict for JSONB storage."""
    if model is None:
        return None
    return model.model_dump(mode="json")


def safe_json_dumps(obj: Any) -> str | None:
    """Safely serialize to JSON string, returning None on failure."""
    if obj is None:
        return None
    try:
        return json.dumps(obj, default=str)
    except (TypeError, ValueError):
        return str(obj)


def truncate_text(text: str | None, max_len: int = 50000) -> str | None:
    """Truncate text to max_len characters."""
    if text is None:
        return None
    if len(text) <= max_len:
        return text
    return text[:max_len] + f"... [truncated, total {len(text)} chars]"


def extract_user_input(messages: list[dict[str, Any]]) -> str:
    """Extract the last user message content from a messages list."""
    for msg in reversed(messages):
        if msg.get("role") == "user":
            content = msg.get("content", "")
            if isinstance(content, str):
                return content
            if isinstance(content, list):
                # Multi-part content — extract text parts
                parts = [
                    p.get("text", "")
                    for p in content
                    if isinstance(p, dict) and p.get("type") == "text"
                ]
                return " ".join(parts)
    return ""
