"""Contribution API — submit anonymized detection results to Navil Cloud.

Uses the same privacy-preserving sanitization as telemetry_sync.py.
Accepts: tool sequences, anomaly types, severity, confidence (no raw payloads).

Can be called from the canary kit to feed data back to the intel pool.

Usage::

    from navil.cloud.contribution_api import ContributionClient

    client = ContributionClient()
    await client.submit_detections(records)
"""

from __future__ import annotations

import hashlib
import logging
import os
import uuid
from typing import Any

logger = logging.getLogger(__name__)

# Cloud endpoint for contributions
_DEFAULT_ENDPOINT = "https://api.navil.ai/v1/threat-intel/contribute"

# Strict allowlist — only these fields may be transmitted
CONTRIBUTION_ALLOWED_FIELDS: frozenset[str] = frozenset(
    {
        "tool_sequence_hash",
        "anomaly_type",
        "severity",
        "confidence",
        "tool_count",
        "unique_tool_count",
        "timestamp",
        "contribution_uuid",
        "source_type",  # "canary", "honeypot", "detector"
        "profile_name",
    }
)

# Fields that MUST NEVER be transmitted
CONTRIBUTION_BANNED_FIELDS: frozenset[str] = frozenset(
    {
        "source_ip",
        "arguments",
        "raw_body",
        "request_headers",
        "content",
        "params",
        "tool_name",  # individual tool names could reveal infrastructure
        "agent_name",
        "path",
        "url",
        "email",
    }
)


def sanitize_record(record: dict[str, Any]) -> dict[str, Any]:
    """Sanitize a single interaction record for contribution.

    Strips all PII, arguments, IPs, and headers.
    Returns only statistical metadata safe for public sharing.

    Args:
        record: Raw honeypot/detection record.

    Returns:
        Sanitized dict containing only allowed fields.

    Raises:
        ValueError: If a banned field would leak through.
    """
    out: dict[str, Any] = {}

    # Hash the tool sequence (not individual tool names)
    tool_name = record.get("tool_name", "")
    if tool_name:
        out["tool_sequence_hash"] = hashlib.sha256(tool_name.encode()).hexdigest()

    # Copy allowed metadata
    for key in ("anomaly_type", "severity", "confidence", "timestamp", "source_type", "profile_name"):
        if key in record:
            out[key] = record[key]

    # Statistical aggregates only
    if "tool_count" in record:
        out["tool_count"] = int(record["tool_count"])
    if "unique_tool_count" in record:
        out["unique_tool_count"] = int(record["unique_tool_count"])

    # Generate deterministic contribution UUID
    uuid_input = f"{out.get('tool_sequence_hash', '')}:{out.get('timestamp', '')}"
    out["contribution_uuid"] = str(uuid.uuid5(uuid.NAMESPACE_URL, uuid_input))

    # Defence-in-depth: verify NO banned field leaked through
    leaked = CONTRIBUTION_BANNED_FIELDS & set(out.keys())
    if leaked:
        raise ValueError(f"Privacy violation: banned fields in contribution: {leaked}")

    # Final allowlist gate
    return {k: v for k, v in out.items() if k in CONTRIBUTION_ALLOWED_FIELDS}


def sanitize_batch(records: list[dict[str, Any]]) -> list[dict[str, Any]]:
    """Sanitize a batch of records for contribution."""
    results: list[dict[str, Any]] = []
    for record in records:
        try:
            results.append(sanitize_record(record))
        except Exception:
            logger.debug("Skipped unsanitizable contribution record")
    return results


class ContributionClient:
    """Client for submitting anonymized detections to Navil Cloud.

    Usage::

        client = ContributionClient()
        result = await client.submit_detections(records)
    """

    def __init__(
        self,
        endpoint: str = _DEFAULT_ENDPOINT,
        api_key: str = "",
    ) -> None:
        self.endpoint = endpoint
        self.api_key = api_key or os.environ.get("NAVIL_API_KEY", "")
        self._http_client: Any = None

    def _get_client(self) -> Any:
        if self._http_client is None:
            import httpx

            headers: dict[str, str] = {"Content-Type": "application/json"}
            if self.api_key:
                headers["Authorization"] = f"Bearer {self.api_key}"
            self._http_client = httpx.AsyncClient(headers=headers, timeout=30.0)
        return self._http_client

    async def submit_detections(
        self,
        records: list[dict[str, Any]],
        source_type: str = "canary",
        profile_name: str = "",
    ) -> dict[str, Any]:
        """Submit anonymized detection records to the cloud.

        Args:
            records: Raw interaction records from honeypot/collector.
            source_type: Type of source ("canary", "honeypot", "detector").
            profile_name: Honeypot profile name (if applicable).

        Returns:
            Summary dict with submitted count and status.
        """
        # Annotate records with source metadata
        annotated = []
        for r in records:
            enriched = dict(r)
            enriched["source_type"] = source_type
            if profile_name:
                enriched["profile_name"] = profile_name
            annotated.append(enriched)

        sanitized = sanitize_batch(annotated)

        if not sanitized:
            return {"submitted": 0, "status": "no_data"}

        try:
            client = self._get_client()
            resp = await client.post(
                self.endpoint,
                json={"contributions": sanitized},
            )

            if resp.status_code < 300:
                logger.info("Contributed %d anonymized detections", len(sanitized))
                return {"submitted": len(sanitized), "status": "ok"}
            else:
                logger.warning("Contribution failed: HTTP %d", resp.status_code)
                return {"submitted": 0, "status": f"error_{resp.status_code}"}

        except ImportError:
            logger.warning("httpx not installed, cannot submit contributions")
            return {"submitted": 0, "status": "no_httpx"}
        except Exception:
            logger.error("Contribution submission failed", exc_info=True)
            return {"submitted": 0, "status": "error"}

    async def close(self) -> None:
        """Clean up HTTP client."""
        if self._http_client:
            await self._http_client.aclose()
            self._http_client = None
