"""Local heuristic PII/secret redaction for text entering persistent data."""

from __future__ import annotations

import re
from dataclasses import dataclass

from cyberbrain26.security_plane.audit import AuditEventType, AuditLog


@dataclass(frozen=True)
class PrivacyFinding:
    category: str
    count: int


@dataclass(frozen=True)
class PrivacyResult:
    text: str
    findings: tuple[PrivacyFinding, ...]

    @property
    def redacted(self) -> bool:
        return bool(self.findings)


class PrivacyGateway:
    """Detect and redact common text PII and secret patterns locally.

    This deterministic filter is a privacy aid, not complete PII detection. It
    records categories and counts without copying matched source values into
    audit events.
    """

    _RULES: tuple[tuple[str, re.Pattern[str], str], ...] = (
        (
            "secret_assignment",
            re.compile(
                r"(?i)\b(password|passwd|secret|api[_-]?key|token|authorization)"
                r"\s*[:=]\s*(['\"]?)[^\s,'\";]+\2"
            ),
            "[REDACTED:SECRET]",
        ),
        (
            "api_token",
            re.compile(r"\b(?:ghp_[A-Za-z0-9]{20,}|sk-[A-Za-z0-9_-]{20,}|AKIA[A-Z0-9]{16})\b"),
            "[REDACTED:SECRET]",
        ),
        (
            "email",
            re.compile(r"(?i)\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b"),
            "[REDACTED:EMAIL]",
        ),
        (
            "phone",
            re.compile(r"(?<!\w)\+?\d[\d(). -]{7,}\d(?!\w)"),
            "[REDACTED:PHONE]",
        ),
    )

    def __init__(self, *, audit_log: AuditLog | None = None) -> None:
        self.audit_log = audit_log

    def redact(self, text: str, *, context: str = "text") -> PrivacyResult:
        """Return sanitized text and non-sensitive finding counts."""
        if not isinstance(text, str):
            raise TypeError("privacy gateway accepts text strings only")
        sanitized = text
        findings: list[PrivacyFinding] = []
        for category, pattern, replacement in self._RULES:
            sanitized, count = pattern.subn(replacement, sanitized)
            if count:
                findings.append(PrivacyFinding(category=category, count=count))
        if findings and self.audit_log is not None:
            self.audit_log.record(
                AuditEventType.DATA_ACCESS,
                action="privacy_redaction",
                resource=context,
                result="redacted",
                metadata={"findings": {item.category: item.count for item in findings}},
            )
        return PrivacyResult(text=sanitized, findings=tuple(findings))


__all__ = ["PrivacyFinding", "PrivacyGateway", "PrivacyResult"]
