
"""
vgovern SDK - Utilities
"""

import logging
import re
import secrets
from typing import Any, Dict, Optional
from uuid import UUID

from .sdk_types import TraceStatus

class TraceLogger(logging.LoggerAdapter):
    """Logger that automatically includes trace_id in all log messages."""

    def __init__(self, logger: logging.Logger, trace_id: Optional[UUID] = None):
        super().__init__(logger, {})
        self.trace_id = trace_id

    def process(self, msg: Any, kwargs: Dict[str, Any]) -> tuple:
        if self.trace_id:
            kwargs.setdefault("extra", {})["trace_id"] = str(self.trace_id)
        return msg, kwargs

    def with_trace(self, trace_id: UUID) -> "TraceLogger":
        return TraceLogger(self.logger, trace_id)

def get_logger(name: str) -> logging.Logger:
    logger = logging.getLogger(name)
    if not logger.handlers:
        handler = logging.StreamHandler()
        formatter = logging.Formatter(
            "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
        )
        handler.setFormatter(formatter)
        logger.addHandler(handler)
        logger.setLevel(logging.INFO)
    return logger

SENSITIVE_PATTERNS = [
    (r"Bearer [a-zA-Z0-9\-_]{20,}", "Bearer <REDACTED>"),
    (r"sk-[a-zA-Z0-9]{32,}", "sk-<REDACTED>"),
    (r"api[_-]?key[\x22\x27\x60:=\s]+[a-zA-Z0-9]{20,}", "api_key=<REDACTED>"),
    (r"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b", "<EMAIL_REDACTED>"),
    (r"\b\d{4}[ -]?\d{4}[ -]?\d{4}[ -]?\d{4}\b", "<CREDIT_CARD_REDACTED>"),
    (r"\b\+?[1-9]?[0-9]{9,15}\b", "<PHONE_REDACTED>"),
    (r"\b\d{3}[ -]?\d{2}[ -]?\d{4}\b", "<SSN_REDACTED>"),
    (r"eyJ[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+", "<JWT_REDACTED>"),
]

def redact_sensitive_data(text: str) -> str:
    if not text:
        return text
    redacted = text
    for pattern, replacement in SENSITIVE_PATTERNS:
        redacted = re.sub(pattern, replacement, redacted, flags=re.IGNORECASE)
    return redacted

def safe_truncate(text: Optional[str], max_length: int = 1000) -> str:
    if not text:
        return ""
    if len(text) <= max_length:
        return text
    return text[:max_length] + "... [truncated]"

def generate_step_id() -> str:
    return f"step_{secrets.token_hex(8)}"

def calculate_cost_usd(
    prompt_tokens: int,
    completion_tokens: int,
    model: str,
    prompt_price_per_1k: float = 0.0001,
    completion_price_per_1k: float = 0.0002,
) -> float:
    prompt_cost = (prompt_tokens / 1000) * prompt_price_per_1k
    completion_cost = (completion_tokens / 1000) * completion_price_per_1k
    return prompt_cost + completion_cost

def mask_api_key(api_key: str, visible_chars: int = 4) -> str:
    if not api_key:
        return ""
    if len(api_key) <= visible_chars:
        return "*" * len(api_key)
    return api_key[:4] + "***" + api_key[-visible_chars:]
