from __future__ import annotations

from datetime import datetime, timedelta, timezone
from typing import Any, Dict, Iterable, Optional


SEVERITY_RISK = {"info": 0, "low": 10, "medium": 25, "high": 70, "critical": 90}


def calculate_threat_score(
    findings: Iterable[Dict[str, Any]],
    *,
    now: Optional[datetime] = None,
    window_hours: int = 24,
) -> Dict[str, Any]:
    """Score recent unique actionable findings; raw telemetry contributes nothing."""
    reference = now or datetime.now(timezone.utc)
    if reference.tzinfo is None:
        reference = reference.replace(tzinfo=timezone.utc)
    cutoff = reference - timedelta(hours=max(1, window_hours))
    unique: Dict[tuple[str, str, str], tuple[datetime, Dict[str, Any]]] = {}

    for finding in findings:
        rule_id = str(finding.get("rule_id") or "").strip()
        if not rule_id:
            continue
        try:
            timestamp = datetime.fromisoformat(str(finding.get("timestamp") or "").replace("Z", "+00:00"))
            if timestamp.tzinfo is None:
                timestamp = timestamp.replace(tzinfo=timezone.utc)
            timestamp = timestamp.astimezone(timezone.utc)
        except (TypeError, ValueError):
            continue
        if timestamp < cutoff or timestamp > reference + timedelta(minutes=5):
            continue
        process = str(finding.get("process") or finding.get("process_name") or finding.get("title") or "Unknown")
        reason = str(finding.get("reason") or finding.get("description") or rule_id)
        key = (rule_id.lower(), process.lower(), reason.lower())
        if key not in unique or timestamp > unique[key][0]:
            unique[key] = (timestamp, finding)

    factors = []
    for timestamp, finding in sorted(unique.values(), key=lambda item: item[0], reverse=True):
        severity = str(finding.get("severity") or "info").lower()
        raw_risk = finding.get("risk_score")
        try:
            contribution = int(raw_risk) if raw_risk is not None else SEVERITY_RISK.get(severity, 0)
        except (TypeError, ValueError):
            contribution = SEVERITY_RISK.get(severity, 0)
        contribution = max(0, min(100, contribution))
        if contribution == 0:
            continue
        factors.append({
            "rule_id": finding.get("rule_id"),
            "process": finding.get("process") or finding.get("process_name") or finding.get("title") or "Unknown",
            "severity": severity,
            "risk_score": contribution,
            "contribution": contribution,
            "timestamp": timestamp.isoformat(timespec="seconds"),
            "reason": finding.get("reason") or finding.get("description") or "Rule finding",
        })

    score = min(100, sum(item["contribution"] for item in factors))
    level = "LOW" if score < 20 else "GUARDED" if score < 40 else "MEDIUM" if score < 60 else "HIGH" if score < 80 else "CRITICAL"
    return {"score": score, "level": level, "factors": factors}
