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 (
    CompareCampaignsRequest,
    CompareAdsetsRequest,
    CompareCreativesRequest,
    CompareTimePeriodsRequest,
    CompareToAccountAverageRequest,
    CalculatePercentilesRequest,
    ToolResult
)
from .base import ToolHandler, _tool_schema

logger = get_logger(__name__)

async def compare_campaigns_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = CompareCampaignsRequest.model_validate(arguments)
    try:
        from ..comparison_tools import ComparisonManager
        manager = ComparisonManager(client)
        
        data = await manager.compare_campaigns(
            campaign_ids=request.campaign_ids,
            start_date=request.start_date,
            end_date=request.end_date,
            metrics=request.metrics,
            include_breakdowns=request.include_breakdowns,
        )
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_compare_campaigns_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def compare_adsets_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = CompareAdsetsRequest.model_validate(arguments)
    try:
        from ..comparison_tools import ComparisonManager
        manager = ComparisonManager(client)
        
        data = await manager.compare_adsets(
            adset_ids=request.adset_ids,
            start_date=request.start_date,
            end_date=request.end_date,
            metrics=request.metrics,
            include_audience_breakdown=request.include_audience_breakdown,
        )
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_compare_adsets_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def compare_creatives_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = CompareCreativesRequest.model_validate(arguments)
    try:
        from ..comparison_tools import ComparisonManager
        manager = ComparisonManager(client)
        
        data = await manager.compare_creatives(
            creative_ids=request.creative_ids,
            start_date=request.start_date,
            end_date=request.end_date,
            metrics=request.metrics,
            include_fatigue_analysis=request.include_fatigue_analysis,
        )
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_compare_creatives_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def compare_time_periods_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = CompareTimePeriodsRequest.model_validate(arguments)
    try:
        from ..comparison_tools import ComparisonManager
        manager = ComparisonManager(client)
        
        data = await manager.compare_time_periods(
            entity_id=request.entity_id,
            entity_type=request.entity_type,
            period_a_start=request.period_a_start,
            period_a_end=request.period_a_end,
            period_b_start=request.period_b_start,
            period_b_end=request.period_b_end,
            metrics=request.metrics,
            include_trend_analysis=request.include_trend_analysis,
        )
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_compare_time_periods_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def compare_to_account_average_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = CompareToAccountAverageRequest.model_validate(arguments)
    try:
        from ..comparison_tools import ComparisonManager
        manager = ComparisonManager(client)
        
        data = await manager.compare_to_account_average(
            entity_id=request.entity_id,
            entity_type=request.entity_type,
            ad_account_id=request.ad_account_id,
            start_date=request.start_date,
            end_date=request.end_date,
            metrics=request.metrics,
            include_percentiles=request.include_percentiles,
        )
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_compare_to_account_average_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def calculate_percentiles_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = CalculatePercentilesRequest.model_validate(arguments)
    try:
        from ..comparison_tools import ComparisonManager
        manager = ComparisonManager(client)
        
        data = await manager.calculate_percentiles(
            ad_account_id=request.ad_account_id,
            entity_type=request.entity_type,
            start_date=request.start_date,
            end_date=request.end_date,
            metrics=request.metrics,
            percentiles=request.percentiles,
        )
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_calculate_percentiles_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.compare_campaigns": (
            mcp_types.Tool(
                name="meta.compare_campaigns",
                description="Compare multiple campaigns side-by-side with performance metrics. Identify best-performing campaigns. Use for campaign benchmarking.",
                inputSchema=_tool_schema(CompareCampaignsRequest),
            ),
            partial(compare_campaigns_handler, client),
        ),
        "meta.compare_adsets": (
            mcp_types.Tool(
                name="meta.compare_adsets",
                description="Compare ad sets side-by-side with targeting and performance breakdown. Find winning audiences. Use for ad set optimization.",
                inputSchema=_tool_schema(CompareAdsetsRequest),
            ),
            partial(compare_adsets_handler, client),
        ),
        "meta.compare_creatives": (
            mcp_types.Tool(
                name="meta.compare_creatives",
                description="Compare creatives with fatigue analysis and engagement metrics. Find winning creative variants. Use for creative testing.",
                inputSchema=_tool_schema(CompareCreativesRequest),
            ),
            partial(compare_creatives_handler, client),
        ),
        "meta.compare_time_periods": (
            mcp_types.Tool(
                name="meta.compare_time_periods",
                description="Compare performance across different time periods. WoW, MoM, YoY analysis with trend detection. Use for period-over-period reporting.",
                inputSchema=_tool_schema(CompareTimePeriodsRequest),
            ),
            partial(compare_time_periods_handler, client),
        ),
        "meta.compare_to_account_average": (
            mcp_types.Tool(
                name="meta.compare_to_account_average",
                description="Compare entity performance to account average. Benchmark against peers. Use for performance normalization.",
                inputSchema=_tool_schema(CompareToAccountAverageRequest),
            ),
            partial(compare_to_account_average_handler, client),
        ),
        "meta.calculate_percentiles": (
            mcp_types.Tool(
                name="meta.calculate_percentiles",
                description="Calculate performance percentiles (top 10%, median, bottom 25%, etc.). Rank entities by metric. Use for percentile analysis.",
                inputSchema=_tool_schema(CalculatePercentilesRequest),
            ),
            partial(calculate_percentiles_handler, client),
        ),
    }
