"""AgentBill Bulk Operations

Batch recording of signals and usage data for improved efficiency.

v8.0.0: Refactored to delegate to _emit_signal() orchestrator via
_build_attributes() + _build_otel_payload_multi_span() for consistency.
"""
import httpx
import time
import uuid
import json
from typing import Optional, Dict, Any, List

from .signals import get_signal_config
from .signal_builder import (
    _build_attributes,
    _build_otel_payload_multi_span,
    _generate_idempotency_key,
)
from .attributes import (
    SDK_VERSION,
    SIGNAL_SPAN_NAME,
)


def record_bulk(
    records: List[Dict[str, Any]],
    *,
    customer_id: Optional[str] = None,
) -> Dict[str, Any]:
    """
    Record multiple signals/events in a single batch request.
    
    More efficient than calling signal() multiple times when you have
    many events to record at once.
    
    Args:
        records: List of record dicts, each containing:
            - event_name (str, required)
            - revenue, metadata, trace_id, span_id, order_id, etc. (optional)
        customer_id: Default customer ID for all records (overridable per-record)
        
    Returns:
        Dict with success status and results per record
        
    Example:
        >>> record_bulk([
        ...     {"event_name": "page_view", "metadata": {"page": "/home"}},
        ...     {"event_name": "purchase", "revenue": 99.99, "order_id": "ord-123"},
        ... ], customer_id="cust-456")
    """
    config = get_signal_config()
    
    api_key = config.get("api_key")
    if not api_key:
        raise ValueError("AgentBill not initialized. Call AgentBill.init() first.")
    
    if not records:
        return {"success": True, "processed": 0, "results": []}
    
    default_customer_id = customer_id or config.get("customer_id")
    base_url = config.get("base_url", "https://api.agentbill.io")
    url = f"{base_url}/functions/v1/otel-collector"
    debug = config.get("debug", False)
    enable_cost_tracing = config.get("enable_cost_tracing", False)
    
    spans = []
    results = []
    
    for i, record in enumerate(records):
        event_name = record.get("event_name")
        if not event_name:
            results.append({"index": i, "success": False, "error": "event_name is required"})
            continue
        
        record_customer_id = record.get("customer_id", default_customer_id)
        generated_trace_id = record.get("trace_id") or uuid.uuid4().hex
        generated_span_id = record.get("span_id") or uuid.uuid4().hex[:16]
        now_ns = int(time.time() * 1_000_000_000)
        
        timestamp_s = int(time.time())
        idempotency_key = record.get("idempotency_key") or _generate_idempotency_key(
            generated_trace_id, event_name, timestamp_s
        )
        
        attributes = _build_attributes(
            event_name=event_name,
            customer_id=record_customer_id,
            agent_id=config.get("agent_id"),
            revenue=record.get("revenue"),
            currency=record.get("currency", "USD"),
            event_type=record.get("event_type"),
            event_value=record.get("event_value"),
            session_id=record.get("session_id"),
            order_id=record.get("order_id"),
            order_external_id=record.get("order_external_id"),
            parent_span_id=record.get("parent_span_id"),
            metadata=record.get("metadata"),
            idempotency_key=idempotency_key,
            enable_cost_tracing=enable_cost_tracing,
            group_by=record.get("group_by"),
            bulk_index=i,
        )
        
        spans.append({
            "traceId": generated_trace_id,
            "spanId": generated_span_id,
            "parentSpanId": record.get("parent_span_id", ""),
            "name": SIGNAL_SPAN_NAME,
            "kind": 1,
            "startTimeUnixNano": str(now_ns),
            "endTimeUnixNano": str(now_ns),
            "attributes": attributes,
            "status": {"code": 1},
        })
        
        results.append({
            "index": i,
            "success": True,
            "trace_id": generated_trace_id,
            "span_id": generated_span_id,
        })
    
    if not spans:
        return {"success": False, "processed": 0, "results": results, "error": "No valid records to process"}
    
    payload = _build_otel_payload_multi_span(
        spans=spans,
        customer_id=default_customer_id or "",
        agent_id=config.get("agent_id", ""),
        is_bulk=True,
    )
    
    try:
        with httpx.Client(timeout=30) as client:
            response = client.post(
                url,
                json=payload,
                headers={"x-api-key": api_key, "Content-Type": "application/json"},
            )
            
            response_data = {}
            body_success = True
            try:
                response_data = response.json()
                body_success = response_data.get("success", True)
            except Exception:
                pass
            
            is_success = response.status_code == 200 and body_success
            
            if debug:
                if is_success:
                    print(f"[AgentBill] ✓ Bulk recorded {len(spans)} signals")
                else:
                    print(f"[AgentBill] ⚠️ Bulk recording failed: {response_data.get('error', response.text)}")
            
            if not is_success:
                for r in results:
                    if r.get("success"):
                        r["success"] = False
                        r["error"] = response_data.get("error", "Bulk request failed")
            
            return {
                "success": is_success,
                "processed": len(spans),
                "results": results,
                "error": response_data.get("error") if not is_success else None,
            }
            
    except Exception as e:
        if debug:
            print(f"[AgentBill] ⚠️ Bulk recording error: {e}")
        
        for r in results:
            if r.get("success"):
                r["success"] = False
                r["error"] = str(e)
        
        return {
            "success": False,
            "processed": 0,
            "results": results,
            "error": str(e),
        }
