"""
AgentDrop Shield -- Metadata extractor for Shield v2.

Converts a local ScanResult into a metadata-only payload suitable
for sending to the server-side classification endpoint.

CRITICAL: This module STRIPS all text content, matched strings,
pattern details, and signal descriptions. Only statistical signals
(counts, scores, category names, boolean flags) are included.

This preserves the zero-knowledge guarantee: the server never sees
file content or extracted text.
"""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any, Optional

from .models import ScanResult


@dataclass
class ShieldMetadata:
    """Metadata payload for server-side classification.

    Contains ONLY statistical signals -- no text content, no matched
    strings, no pattern details. Safe to transmit to the server
    without breaking zero-knowledge.
    """

    file_metadata: dict[str, Any]
    """File type, size, and structural info."""

    layer_results: dict[str, Any]
    """Per-layer scores, finding counts, and category names."""

    local_verdict: dict[str, Any]
    """Client-side verdict: threat level, score, safe flag."""

    sender_id: Optional[str] = None
    """Sender agent identifier (if provided)."""

    sender_account_id: Optional[str] = None
    """Sender account identifier (if provided)."""


def extract_metadata(
    scan_result: ScanResult,
    file_info: dict[str, Any],
    sender_id: Optional[str] = None,
    sender_account_id: Optional[str] = None,
) -> ShieldMetadata:
    """Extract metadata from a local ScanResult.

    Strips ALL text content -- only keeps counts, scores, and
    category names. The returned ShieldMetadata is safe to POST
    to the server without breaking zero-knowledge.

    Args:
        scan_result: The full local scan result.
        file_info: Dict with 'type' and 'size' keys.
        sender_id: Optional sender agent ID.
        sender_account_id: Optional sender account ID.

    Returns:
        ShieldMetadata with statistical signals only.
    """
    details = scan_result.details

    # ── File metadata ─────────────────────────────────────────────
    text_ext = details.get("text_extraction", {})
    file_metadata = {
        "type": file_info.get("type", "unknown"),
        "size": file_info.get("size", 0),
        "text_density": (
            text_ext.get("total_chars", 0) / max(file_info.get("size", 1), 1)
        ),
    }

    # ── Resource guard ────────────────────────────────────────────
    rg = details.get("resource_guard", {})
    resource_guard = {
        "passed": rg.get("passed", True),
        "flags": [k for k, v in rg.items() if k not in ("passed", "reason") and v],
    }

    # ── Format validation ─────────────────────────────────────────
    fv = details.get("format_validation", {})
    fv_flags = []
    if fv.get("type_mismatch"):
        fv_flags.append("type_mismatch")
    if fv.get("is_polyglot"):
        fv_flags.append("is_polyglot")
    format_validation = {
        "passed": not fv.get("type_mismatch", False) and not fv.get("is_polyglot", False),
        "flags": fv_flags,
        "confidence": 1.0 if fv_flags else 0.0,
    }

    # ── Injection detection (STRIP all text) ──────────────────────
    findings = scan_result.injection_findings
    if findings:
        confidences = [f.confidence for f in findings]
        categories = list({f.pattern_name for f in findings})
        injection_detection = {
            "findings_count": len(findings),
            "categories": categories,
            "max_confidence": max(confidences),
            "avg_confidence": sum(confidences) / len(confidences),
            "languages": [],  # Language detection not stored per-finding in Python SDK
        }
    else:
        injection_detection = {
            "findings_count": 0,
            "categories": [],
            "max_confidence": 0.0,
            "avg_confidence": 0.0,
            "languages": [],
        }

    # ── Intent classification (scores only) ───────────────────────
    ic = details.get("intent_classification", {})
    intent_classification = {
        "score": scan_result.intent_score,
        "top_intents": [],  # We don't expose signal names as "intents"
    }

    # ── Semantic analysis (scores only) ───────────────────────────
    sa = details.get("semantic_analysis", {})
    semantic_analysis = {
        "score": scan_result.semantic_score,
        "categories": [],  # Strip signal details
    }

    # ── Local verdict ─────────────────────────────────────────────
    # Use intent_score as the primary "score" since there's no single
    # composite score in the Python ScanResult.
    max_conf = max((f.confidence for f in findings), default=0.0)
    blended_score = (
        max_conf * 0.4
        + scan_result.intent_score * 0.3
        + scan_result.semantic_score * 0.3
    )

    local_verdict = {
        "threat": scan_result.threat_level.name,
        "score": round(blended_score, 4),
        "safe": scan_result.is_clean,
    }

    return ShieldMetadata(
        file_metadata=file_metadata,
        layer_results={
            "resource_guard": resource_guard,
            "format_validation": format_validation,
            "injection_detection": injection_detection,
            "intent_classification": intent_classification,
            "semantic_analysis": semantic_analysis,
        },
        local_verdict=local_verdict,
        sender_id=sender_id,
        sender_account_id=sender_account_id,
    )
