"""
Conversation-level security audit and risk scoring.
"""

from dataclasses import dataclass, field
from typing import List

from .injection import detect_injection
from .pii import redact
from .output import enforce


@dataclass
class Finding:
    turn: int
    role: str
    severity: str        # "high" | "medium" | "low"
    category: str        # "injection" | "pii" | "output_anomaly"
    description: str
    risk_contribution: float


@dataclass
class AuditReport:
    risk_score: float
    findings: List[Finding] = field(default_factory=list)
    recommendations: List[str] = field(default_factory=list)
    turn_count: int = 0

    def __repr__(self) -> str:
        lines = [
            "=" * 52,
            f"  StripLLM Audit Report",
            f"  Risk Score : {self.risk_score:.2f} / 1.00",
            f"  Turns      : {self.turn_count}",
            f"  Findings   : {len(self.findings)}",
            "=" * 52,
        ]
        if self.findings:
            lines.append("  Findings:")
            for f in self.findings:
                lines.append(
                    f"    [Turn {f.turn}] [{f.severity.upper()}] {f.category}: {f.description}"
                )
        if self.recommendations:
            lines.append("  Recommendations:")
            for r in self.recommendations:
                lines.append(f"    • {r}")
        lines.append("=" * 52)
        return "\n".join(lines)


def audit(conversation: list) -> AuditReport:
    """
    Perform a full security audit of a conversation.

    Args:
        conversation: List of dicts with "role" ("user"|"assistant") and "content" (str).

    Returns:
        AuditReport with risk_score, findings list, and recommendations.
    """
    findings: List[Finding] = []
    recommendations: set = set()
    cumulative_risk = 0.0

    for i, turn in enumerate(conversation):
        role = turn.get("role", "unknown")
        content = turn.get("content", "")
        turn_risk = 0.0

        # --- Injection check (user turns primarily, but also check assistant turns for indirect injection) ---
        inj = detect_injection(content)
        if inj.detected:
            severity = "high" if inj.risk_score >= 0.7 else "medium"
            findings.append(Finding(
                turn=i + 1,
                role=role,
                severity=severity,
                category="injection",
                description=f"Injection signals detected (score={inj.risk_score:.2f}, "
                            f"patterns={len(inj.matched_patterns)})",
                risk_contribution=inj.risk_score * 0.5,
            ))
            turn_risk += inj.risk_score * 0.5
            recommendations.add("Validate all user inputs with strip.clean() before passing to LLM.")
            if severity == "high":
                recommendations.add("Consider blocking or flagging this conversation for human review.")

        # --- PII check ---
        redaction = redact(content)
        pii_count = sum(redaction.entity_counts.values())
        if pii_count > 0:
            severity = "high" if pii_count >= 3 else "medium" if pii_count == 2 else "low"
            entity_summary = ", ".join(
                f"{k}×{v}" for k, v in redaction.entity_counts.items()
            )
            findings.append(Finding(
                turn=i + 1,
                role=role,
                severity=severity,
                category="pii",
                description=f"PII detected: {entity_summary}",
                risk_contribution=min(0.4, pii_count * 0.1),
            ))
            turn_risk += min(0.4, pii_count * 0.1)
            recommendations.add("Use strip.redact() to strip PII before sending to the LLM.")
            if any(k in redaction.entity_counts for k in ("SSN", "CREDIT_CARD", "PASSPORT")):
                recommendations.add("Highly sensitive PII detected (SSN/CC/Passport). Review compliance requirements (HIPAA, PCI-DSS).")

        # --- Output anomaly check (assistant turns) ---
        if role == "assistant":
            validation = enforce(content, check_leaks=True, check_urls=True)
            if validation.warnings:
                for warning in validation.warnings:
                    findings.append(Finding(
                        turn=i + 1,
                        role=role,
                        severity="medium",
                        category="output_anomaly",
                        description=warning,
                        risk_contribution=0.2,
                    ))
                    turn_risk += 0.2
                recommendations.add("Validate assistant outputs with strip.enforce() to catch leaks and hallucinations.")

        cumulative_risk += turn_risk

    # Normalize: average per-turn risk, capped at 1.0
    if conversation:
        risk_score = min(1.0, cumulative_risk / len(conversation))
    else:
        risk_score = 0.0

    if not recommendations and risk_score == 0.0:
        recommendations.add("No significant risks detected. Maintain current security posture.")

    return AuditReport(
        risk_score=round(risk_score, 3),
        findings=findings,
        recommendations=sorted(recommendations),
        turn_count=len(conversation),
    )
