"""Conversions API (CAPI) tools for Meta Marketing API.

This module provides tools for server-side event tracking, offline conversions,
and CAPI diagnostics.
"""

from __future__ import annotations

from typing import Any, Dict
import hashlib
import time

from .errors import MetaApiError
from .logging import get_logger
from .meta_client import get_client
from .schemas import ToolResult

logger = get_logger(__name__)


def _hash_data(value: str) -> str:
    """Hash data for CAPI (SHA256)."""
    return hashlib.sha256(value.lower().strip().encode()).hexdigest()


async def send_capi_event_handler(arguments: Dict[str, Any]) -> ToolResult:
    """Send a server-side conversion event via Conversions API.
    
    Args:
        arguments: {
            "pixel_id": "123",
            "event_name": "Purchase",
            "event_time": 1234567890,
            "user_data": {
                "em": "email@example.com",  # Will be hashed
                "ph": "+1234567890",  # Will be hashed
                "client_ip_address": "1.2.3.4",
                "client_user_agent": "Mozilla/5.0...",
                "fbc": "fb.1.xxx",  # Facebook click ID
                "fbp": "fb.1.xxx",  # Facebook browser ID
            },
            "custom_data": {
                "value": 99.99,
                "currency": "USD",
                "content_ids": ["SKU123"],
                "content_type": "product"
            },
            "action_source": "website"
        }
        
    Returns:
        ToolResult with event send status
    """
    try:
        client = get_client()
        pixel_id = arguments.get("pixel_id")
        
        if not pixel_id:
            return ToolResult(ok=False, error={"message": "pixel_id is required"})
        
        # Hash PII fields if provided
        user_data = arguments.get("user_data", {})
        hashed_user_data = {}
        
        # Fields that need hashing
        hash_fields = ["em", "ph", "fn", "ln", "ct", "st", "zp", "country"]
        
        for field in hash_fields:
            if field in user_data:
                hashed_user_data[field] = _hash_data(str(user_data[field]))
        
        # Fields that don't need hashing
        no_hash_fields = ["client_ip_address", "client_user_agent", "fbc", "fbp", "external_id"]
        for field in no_hash_fields:
            if field in user_data:
                hashed_user_data[field] = user_data[field]
        
        # Build event data
        event_data = {
            "event_name": arguments.get("event_name"),
            "event_time": arguments.get("event_time", int(time.time())),
            "user_data": hashed_user_data,
            "action_source": arguments.get("action_source", "website"),
        }
        
        # Add custom data if provided
        if "custom_data" in arguments:
            event_data["custom_data"] = arguments["custom_data"]
        
        # Add optional fields
        if "event_source_url" in arguments:
            event_data["event_source_url"] = arguments["event_source_url"]
        if "event_id" in arguments:
            event_data["event_id"] = arguments["event_id"]
        if "opt_out" in arguments:
            event_data["opt_out"] = arguments["opt_out"]
        
        # Send event
        response = await client.post(
            f"{pixel_id}/events",
            body={"data": [event_data]}
        )
        
        return ToolResult(ok=True, data=response)
    except MetaApiError as exc:
        logger.error("send_capi_event_failed", **exc.to_dict())
        return ToolResult(ok=False, error=exc.to_dict())


async def send_capi_batch_events_handler(arguments: Dict[str, Any]) -> ToolResult:
    """Send multiple server-side events in a batch via Conversions API.
    
    Args:
        arguments: {
            "pixel_id": "123",
            "events": [
                {
                    "event_name": "Purchase",
                    "event_time": 1234567890,
                    "user_data": {...},
                    "custom_data": {...}
                },
                ...
            ]
        }
        
    Returns:
        ToolResult with batch send status
    """
    try:
        client = get_client()
        pixel_id = arguments.get("pixel_id")
        events = arguments.get("events", [])
        
        if not pixel_id:
            return ToolResult(ok=False, error={"message": "pixel_id is required"})
        
        if not events:
            return ToolResult(ok=False, error={"message": "events list is required"})
        
        # Process each event
        processed_events = []
        for event in events:
            user_data = event.get("user_data", {})
            hashed_user_data = {}
            
            # Hash PII fields
            hash_fields = ["em", "ph", "fn", "ln", "ct", "st", "zp", "country"]
            for field in hash_fields:
                if field in user_data:
                    hashed_user_data[field] = _hash_data(str(user_data[field]))
            
            # Non-hashed fields
            no_hash_fields = ["client_ip_address", "client_user_agent", "fbc", "fbp", "external_id"]
            for field in no_hash_fields:
                if field in user_data:
                    hashed_user_data[field] = user_data[field]
            
            processed_event = {
                "event_name": event.get("event_name"),
                "event_time": event.get("event_time", int(time.time())),
                "user_data": hashed_user_data,
                "action_source": event.get("action_source", "website"),
            }
            
            if "custom_data" in event:
                processed_event["custom_data"] = event["custom_data"]
            if "event_source_url" in event:
                processed_event["event_source_url"] = event["event_source_url"]
            if "event_id" in event:
                processed_event["event_id"] = event["event_id"]
            
            processed_events.append(processed_event)
        
        # Send batch
        response = await client.post(
            f"{pixel_id}/events",
            body={"data": processed_events}
        )
        
        return ToolResult(
            ok=True,
            data={
                "events_sent": len(processed_events),
                "response": response,
            }
        )
    except MetaApiError as exc:
        logger.error("send_capi_batch_events_failed", **exc.to_dict())
        return ToolResult(ok=False, error=exc.to_dict())


async def test_capi_event_handler(arguments: Dict[str, Any]) -> ToolResult:
    """Send a test event via Conversions API.
    
    Args:
        arguments: {
            "pixel_id": "123",
            "test_event_code": "TEST12345",
            "event_name": "Purchase",
            "user_data": {...},
            "custom_data": {...}
        }
        
    Returns:
        ToolResult with test event status
    """
    try:
        client = get_client()
        pixel_id = arguments.get("pixel_id")
        test_event_code = arguments.get("test_event_code")
        
        if not pixel_id or not test_event_code:
            return ToolResult(ok=False, error={"message": "pixel_id and test_event_code are required"})
        
        # Hash user data
        user_data = arguments.get("user_data", {})
        hashed_user_data = {}
        
        hash_fields = ["em", "ph", "fn", "ln"]
        for field in hash_fields:
            if field in user_data:
                hashed_user_data[field] = _hash_data(str(user_data[field]))
        
        # Build test event
        event_data = {
            "event_name": arguments.get("event_name", "PageView"),
            "event_time": int(time.time()),
            "user_data": hashed_user_data,
            "action_source": "website",
        }
        
        if "custom_data" in arguments:
            event_data["custom_data"] = arguments["custom_data"]
        
        # Send with test event code
        response = await client.post(
            f"{pixel_id}/events",
            body={
                "data": [event_data],
                "test_event_code": test_event_code,
            }
        )
        
        return ToolResult(
            ok=True,
            data={
                "message": "Test event sent. Check Events Manager for results.",
                "response": response,
            }
        )
    except MetaApiError as exc:
        logger.error("test_capi_event_failed", **exc.to_dict())
        return ToolResult(ok=False, error=exc.to_dict())


async def diagnose_capi_handler(arguments: Dict[str, Any]) -> ToolResult:
    """Diagnose Conversions API setup and event quality.
    
    Args:
        arguments: {"pixel_id": "123"}
        
    Returns:
        ToolResult with diagnostic information
    """
    try:
        client = get_client()
        pixel_id = arguments.get("pixel_id")
        
        if not pixel_id:
            return ToolResult(ok=False, error={"message": "pixel_id is required"})
        
        # Get pixel stats
        stats_response = await client.get(
            f"{pixel_id}",
            params={"fields": "id,name,is_created_by_business,is_unavailable,last_fired_time"}
        )
        
        # Get event stats (if available)
        try:
            event_stats = await client.get(
                f"{pixel_id}/stats",
                params={"fields": "count,timestamp"}
            )
        except MetaApiError:
            event_stats = {"message": "Event stats not available"}
        
        # Get server events stats
        try:
            server_stats = await client.get(
                f"{pixel_id}/server_events_stats",
                params={"fields": "count,match_rate_approx"}
            )
        except MetaApiError:
            server_stats = {"message": "Server events stats not available"}
        
        return ToolResult(
            ok=True,
            data={
                "pixel_info": stats_response,
                "event_stats": event_stats,
                "server_stats": server_stats,
                "recommendations": [
                    "Ensure all user_data fields are properly hashed",
                    "Include fbc and fbp parameters for better matching",
                    "Use event_id to deduplicate browser and server events",
                    "Monitor match rate in Events Manager",
                ]
            }
        )
    except MetaApiError as exc:
        logger.error("diagnose_capi_failed", pixel_id=pixel_id, **exc.to_dict())
        return ToolResult(ok=False, error=exc.to_dict())


async def upload_offline_conversions_handler(arguments: Dict[str, Any]) -> ToolResult:
    """Upload offline conversion events.
    
    Args:
        arguments: {
            "dataset_id": "123",
            "events": [
                {
                    "event_name": "Purchase",
                    "event_time": 1234567890,
                    "match_keys": {
                        "email": "user@example.com",  # Will be hashed
                        "phone": "+1234567890"  # Will be hashed
                    },
                    "value": 99.99,
                    "currency": "USD"
                }
            ]
        }
        
    Returns:
        ToolResult with upload status
    """
    try:
        client = get_client()
        dataset_id = arguments.get("dataset_id")
        events = arguments.get("events", [])
        
        if not dataset_id:
            return ToolResult(ok=False, error={"message": "dataset_id is required"})
        
        if not events:
            return ToolResult(ok=False, error={"message": "events list is required"})
        
        # Process events
        processed_events = []
        for event in events:
            match_keys = event.get("match_keys", {})
            hashed_match_keys = {}
            
            # Hash match keys
            if "email" in match_keys:
                hashed_match_keys["email"] = _hash_data(match_keys["email"])
            if "phone" in match_keys:
                hashed_match_keys["phone"] = _hash_data(match_keys["phone"])
            if "madid" in match_keys:
                hashed_match_keys["madid"] = match_keys["madid"]
            
            processed_event = {
                "event_name": event.get("event_name"),
                "event_time": event.get("event_time", int(time.time())),
                "match_keys": hashed_match_keys,
            }
            
            # Add value and currency if provided
            if "value" in event:
                processed_event["value"] = event["value"]
            if "currency" in event:
                processed_event["currency"] = event["currency"]
            
            processed_events.append(processed_event)
        
        # Upload
        response = await client.post(
            f"{dataset_id}/events",
            body={"data": processed_events}
        )
        
        return ToolResult(
            ok=True,
            data={
                "events_uploaded": len(processed_events),
                "response": response,
            }
        )
    except MetaApiError as exc:
        logger.error("upload_offline_conversions_failed", **exc.to_dict())
        return ToolResult(ok=False, error=exc.to_dict())

