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 BatchResult, MetaClient
from ..schemas import (
    CreateAdObjectRequest,
    UpdateAdObjectRequest,
    BulkStatusUpdateRequest,
    ToolResult
)
from .base import ToolHandler, _tool_schema

logger = get_logger(__name__)

async def create_ad_object_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = CreateAdObjectRequest.model_validate(arguments)
    try:
        response = await client.post(
            f"{request.parent_id}/{request.resource}",
            body=request.payload,
            encoding=request.encoding,
        )
        return ToolResult(ok=True, data=response)
    except MetaApiError as exc:
        logger.error("tool_create_failed", **exc.to_dict())
        return ToolResult(ok=False, error=exc.to_dict())

async def update_ad_object_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = UpdateAdObjectRequest.model_validate(arguments)
    try:
        response = await client.post(
            f"{request.object_id}",
            body=request.updates,
            encoding=request.encoding,
        )
        return ToolResult(ok=True, data=response)
    except MetaApiError as exc:
        logger.error("tool_update_failed", **exc.to_dict())
        return ToolResult(ok=False, error=exc.to_dict())

async def bulk_status_update_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = BulkStatusUpdateRequest.model_validate(arguments)
    try:
        # Create batch operations for each object
        operations = []
        for object_id in request.object_ids:
            operations.append({
                "method": "POST",
                "relative_url": f"{object_id}",
                "body": f"status={request.status}"
            })
        
        response = await client.batch(operations)
        if isinstance(response, BatchResult):
            payload: Dict[str, Any] = response.to_dict()
        else:
            payload = response
        return ToolResult(ok=True, data=payload)
    except MetaApiError as exc:
        logger.error("tool_bulk_status_update_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": (
            mcp_types.Tool(
                name="meta.create",
                description="Create campaigns, ad sets, or ads in Meta Ads Manager. Supports all campaign objectives, targeting options, and creative configurations. Use for launching new advertising campaigns.",
                inputSchema=_tool_schema(CreateAdObjectRequest),
            ),
            partial(create_ad_object_handler, client),
        ),
        "meta.update": (
            mcp_types.Tool(
                name="meta.update",
                description="Update campaigns, ad sets, or ads. Modify budgets, bids, targeting, schedules, and status. Use for optimization adjustments and campaign management.",
                inputSchema=_tool_schema(UpdateAdObjectRequest),
            ),
            partial(update_ad_object_handler, client),
        ),
        "meta.bulk_status_update": (
            mcp_types.Tool(
                name="meta.bulk_status_update",
                description="Bulk update status to ACTIVE, PAUSED, or ARCHIVED for multiple campaigns, ad sets, or ads simultaneously. Use for mass campaign control and emergency pausing.",
                inputSchema=_tool_schema(BulkStatusUpdateRequest),
            ),
            partial(bulk_status_update_handler, client),
        ),
    }
