from typing import Any, Dict, Tuple
from functools import partial

from mcp import types as mcp_types

from ..errors import MetaApiError
from ..logging import get_logger
from ..meta_client import MetaClient
from ..schemas import (
    CreatePixelRequest,
    UpdatePixelRequest,
    GetPixelRequest,
    PixelStatsRequest,
    CreateCustomConversionRequest,
    ListConversionsRequest,
    ServerSideEventRequest,
    GraphBodyEncoding,
    ToolResult
)
from .base import ToolHandler, _tool_schema

logger = get_logger(__name__)

async def create_pixel_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = CreatePixelRequest.model_validate(arguments)
    try:
        payload = {
            "name": request.name,
        }
        if request.description:
            payload["description"] = request.description
            
        response = await client.post(
            f"{request.ad_account_id}/adspixels",
            body=payload,
            encoding=GraphBodyEncoding.FORM,
        )
        return ToolResult(ok=True, data=response)
    except MetaApiError as exc:
        logger.error("tool_create_pixel_failed", **exc.to_dict())
        return ToolResult(ok=False, error=exc.to_dict())

async def update_pixel_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = UpdatePixelRequest.model_validate(arguments)
    try:
        payload = {}
        if request.name:
            payload["name"] = request.name
        if request.description:
            payload["description"] = request.description
            
        response = await client.post(
            f"{request.pixel_id}",
            body=payload,
            encoding=GraphBodyEncoding.FORM,
        )
        return ToolResult(ok=True, data=response)
    except MetaApiError as exc:
        logger.error("tool_update_pixel_failed", **exc.to_dict())
        return ToolResult(ok=False, error=exc.to_dict())

async def get_pixel_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = GetPixelRequest.model_validate(arguments)
    try:
        params = {
            "fields": ",".join(request.fields),
        }
        
        response = await client.get(
            f"{request.pixel_id}",
            params=params,
        )
        return ToolResult(ok=True, data=response)
    except MetaApiError as exc:
        logger.error("tool_get_pixel_failed", **exc.to_dict())
        return ToolResult(ok=False, error=exc.to_dict())

async def get_pixel_stats_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = PixelStatsRequest.model_validate(arguments)
    try:
        params = {
            "start_time": request.start_time,
            "end_time": request.end_time,
            "aggregation": request.aggregation,
        }
        
        response = await client.get(
            f"{request.pixel_id}/stats",
            params=params,
        )
        return ToolResult(ok=True, data=response)
    except MetaApiError as exc:
        logger.error("tool_get_pixel_stats_failed", **exc.to_dict())
        return ToolResult(ok=False, error=exc.to_dict())

async def create_custom_conversion_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = CreateCustomConversionRequest.model_validate(arguments)
    try:
        payload = {
            "name": request.name,
            "pixel": request.pixel_id,
            "event_name": request.event_name,
        }
        if request.value:
            payload["value"] = request.value
        if request.currency:
            payload["currency"] = request.currency
            
        response = await client.post(
            f"{request.ad_account_id}/customconversions",
            body=payload,
            encoding=GraphBodyEncoding.FORM,
        )
        return ToolResult(ok=True, data=response)
    except MetaApiError as exc:
        logger.error("tool_create_custom_conversion_failed", **exc.to_dict())
        return ToolResult(ok=False, error=exc.to_dict())

async def list_conversions_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = ListConversionsRequest.model_validate(arguments)
    try:
        params = {
            "fields": ",".join(request.fields),
            "limit": request.limit,
        }
        
        response = await client.get(
            f"{request.ad_account_id}/customconversions",
            params=params,
        )
        return ToolResult(ok=True, data=response)
    except MetaApiError as exc:
        logger.error("tool_list_conversions_failed", **exc.to_dict())
        return ToolResult(ok=False, error=exc.to_dict())

async def send_server_side_event_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = ServerSideEventRequest.model_validate(arguments)
    try:
        payload = {
            "data": request.events,
            "access_token": request.access_token,
        }
        if request.test_event_code:
            payload["test_event_code"] = request.test_event_code
        if request.partner_agent:
            payload["partner_agent"] = request.partner_agent
            
        response = await client.post(
            f"{request.pixel_id}/events",
            body=payload,
            encoding=GraphBodyEncoding.JSON,
        )
        return ToolResult(ok=True, data=response)
    except MetaApiError as exc:
        logger.error("tool_send_server_side_event_failed", **exc.to_dict())
        return ToolResult(ok=False, error=exc.to_dict())

def get_tools(client: MetaClient) -> Dict[str, Tuple[mcp_types.Tool, ToolHandler]]:
    return {
        "meta.create_pixel": (
            mcp_types.Tool(
                name="meta.create_pixel",
                description="Create a Meta Pixel for website event tracking. Enable conversion tracking, remarketing, and analytics. Use for pixel setup.",
                inputSchema=_tool_schema(CreatePixelRequest),
            ),
            partial(create_pixel_handler, client),
        ),
        "meta.update_pixel": (
            mcp_types.Tool(
                name="meta.update_pixel",
                description="Update a Meta Pixel name or configuration. Modify pixel settings without recreation. Use for pixel management.",
                inputSchema=_tool_schema(UpdatePixelRequest),
            ),
            partial(update_pixel_handler, client),
        ),
        "meta.get_pixel": (
            mcp_types.Tool(
                name="meta.get_pixel",
                description="Get Pixel details including status, last fired time, and configuration. View pixel health. Use for pixel monitoring.",
                inputSchema=_tool_schema(GetPixelRequest),
            ),
            partial(get_pixel_handler, client),
        ),
        "meta.get_pixel_stats": (
            mcp_types.Tool(
                name="meta.get_pixel_stats",
                description="Get Pixel statistics including event counts and trends over time. Track pixel fire volume. Use for pixel health monitoring.",
                inputSchema=_tool_schema(PixelStatsRequest),
            ),
            partial(get_pixel_stats_handler, client),
        ),
        "meta.create_custom_conversion": (
            mcp_types.Tool(
                name="meta.create_custom_conversion",
                description="Create a Custom Conversion based on URL rules or events. Define conversion value for optimization. Use for conversion tracking setup.",
                inputSchema=_tool_schema(CreateCustomConversionRequest),
            ),
            partial(create_custom_conversion_handler, client),
        ),
        "meta.list_conversions": (
            mcp_types.Tool(
                name="meta.list_conversions",
                description="List Custom Conversions in ad account with status and rules. View all tracked conversions. Use for conversion management.",
                inputSchema=_tool_schema(ListConversionsRequest),
            ),
            partial(list_conversions_handler, client),
        ),
        "meta.send_server_side_event": (
            mcp_types.Tool(
                name="meta.send_server_side_event",
                description="Send server-side events via Conversions API (CAPI). Track purchases, leads, and custom events server-side. Use for enhanced tracking.",
                inputSchema=_tool_schema(ServerSideEventRequest),
            ),
            partial(send_server_side_event_handler, client),
        ),
    }
