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

from mcp import types as mcp_types

from ..logging import get_logger
from ..meta_client import MetaClient
from ..schemas import (
    SearchQueryRequest,
    CreateTagRequest,
    TagCampaignRequest,
    GetCampaignTagsRequest,
    ToolResult
)
from .base import ToolHandler, _tool_schema

logger = get_logger(__name__)

async def search_campaigns_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = SearchQueryRequest.model_validate(arguments)
    try:
        from ..search import AdvancedSearchEngine, SearchQuery, FilterCondition, SortCondition, FilterOperator, SortDirection
        search_engine = AdvancedSearchEngine(client)
        
        # Convert request to search query
        filters = []
        if request.filters:
            for filter_req in request.filters:
                filters.append(FilterCondition(
                    field=filter_req.field,
                    operator=FilterOperator(filter_req.operator),
                    value=filter_req.value,
                    case_sensitive=filter_req.case_sensitive,
                ))
        
        sort_conditions = []
        if request.sort_conditions:
            for sort_req in request.sort_conditions:
                sort_conditions.append(SortCondition(
                    field=sort_req.field,
                    direction=SortDirection(sort_req.direction),
                ))
        
        search_query = SearchQuery(
            text_query=request.text_query,
            filters=filters,
            sort_conditions=sort_conditions,
            tags=request.tags,
            limit=request.limit,
            offset=request.offset,
        )
        
        results = await search_engine.search_campaigns(request.ad_account_id, search_query)
        
        return ToolResult(ok=True, data=[{
            "id": result.id,
            "name": result.name,
            "type": result.type,
            "status": result.status,
            "score": result.score,
            "matched_fields": result.matched_fields,
            "metadata": result.metadata,
        } for result in results])
    except Exception as exc:
        logger.error("tool_search_campaigns_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def create_tag_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = CreateTagRequest.model_validate(arguments)
    try:
        from ..search import AdvancedSearchEngine
        search_engine = AdvancedSearchEngine(client)
        
        tag = await search_engine.create_tag(
            ad_account_id=request.ad_account_id,
            name=request.name,
            color=request.color,
            description=request.description,
        )
        
        return ToolResult(ok=True, data={
            "tag_id": tag.tag_id,
            "name": tag.name,
            "color": tag.color,
            "description": tag.description,
        })
    except Exception as exc:
        logger.error("tool_create_tag_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def tag_campaign_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = TagCampaignRequest.model_validate(arguments)
    try:
        from ..search import AdvancedSearchEngine
        search_engine = AdvancedSearchEngine(client)
        
        success = await search_engine.tag_campaign(
            campaign_id=request.campaign_id,
            tag_id=request.tag_id,
        )
        
        return ToolResult(ok=True, data={"tagged": success})
    except Exception as exc:
        logger.error("tool_tag_campaign_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def get_campaign_tags_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = GetCampaignTagsRequest.model_validate(arguments)
    try:
        from ..search import AdvancedSearchEngine
        search_engine = AdvancedSearchEngine(client)
        
        tags = await search_engine.get_campaign_tags(request.campaign_id)
        
        return ToolResult(ok=True, data=[{
            "tag_id": tag.tag_id,
            "name": tag.name,
            "color": tag.color,
            "description": tag.description,
        } for tag in tags])
    except Exception as exc:
        logger.error("tool_get_campaign_tags_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

def get_tools(client: MetaClient) -> Dict[str, Tuple[mcp_types.Tool, ToolHandler]]:
    return {
        "meta.search_campaigns": (
            mcp_types.Tool(
                name="meta.search_campaigns",
                description="Search campaigns with text queries, filters, and sorting. Find campaigns by name, status, or metrics. Use for campaign discovery.",
                inputSchema=_tool_schema(SearchQueryRequest),
            ),
            partial(search_campaigns_handler, client),
        ),
        "meta.create_tag": (
            mcp_types.Tool(
                name="meta.create_tag",
                description="Create custom tags for organizing campaigns by project, season, or team. Enable campaign categorization. Use for campaign organization.",
                inputSchema=_tool_schema(CreateTagRequest),
            ),
            partial(create_tag_handler, client),
        ),
        "meta.tag_campaign": (
            mcp_types.Tool(
                name="meta.tag_campaign",
                description="Apply a tag to a campaign for organization and filtering. Label campaigns for easy retrieval. Use for campaign tagging.",
                inputSchema=_tool_schema(TagCampaignRequest),
            ),
            partial(tag_campaign_handler, client),
        ),
        "meta.get_campaign_tags": (
            mcp_types.Tool(
                name="meta.get_campaign_tags",
                description="Get all tags applied to a campaign. View campaign labels and categories. Use for tag management.",
                inputSchema=_tool_schema(GetCampaignTagsRequest),
            ),
            partial(get_campaign_tags_handler, client),
        ),
    }
