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 (
    CampaignPerformanceHistoryRequest,
    SpendTrendsRequest,
    AudiencePerformanceHistoryRequest,
    CreativePerformanceHistoryRequest,
    HourlyBreakdownRequest,
    ComparePeriodsRequest,
    PerformanceByDemographicsRequest,
    PerformanceByDeviceRequest,
    PerformanceByPlacementRequest,
    PerformanceByTimeRequest,
    ToolResult
)
from .base import ToolHandler, _tool_schema

logger = get_logger(__name__)

async def campaign_performance_history_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = CampaignPerformanceHistoryRequest.model_validate(arguments)
    try:
        from ..data_retrievers import HistoricalDataRetriever
        retriever = HistoricalDataRetriever(client)
        
        data = await retriever.get_campaign_performance_history(
            campaign_id=request.campaign_id,
            start_date=request.start_date,
            end_date=request.end_date,
            breakdowns=request.breakdowns,
            fields=request.fields,
            time_increment=request.time_increment,
        )
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_campaign_performance_history_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def spend_trends_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = SpendTrendsRequest.model_validate(arguments)
    try:
        from ..data_retrievers import HistoricalDataRetriever
        retriever = HistoricalDataRetriever(client)
        
        data = await retriever.get_spend_trends(
            ad_account_id=request.ad_account_id,
            start_date=request.start_date,
            end_date=request.end_date,
            group_by=request.group_by,
            include_forecast=request.include_forecast,
        )
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_spend_trends_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def audience_performance_history_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = AudiencePerformanceHistoryRequest.model_validate(arguments)
    try:
        from ..data_retrievers import HistoricalDataRetriever
        retriever = HistoricalDataRetriever(client)
        
        data = await retriever.get_audience_performance_history(
            ad_account_id=request.ad_account_id,
            start_date=request.start_date,
            end_date=request.end_date,
            audience_ids=request.audience_ids,
            breakdowns=request.breakdowns,
        )
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_audience_performance_history_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def creative_performance_history_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = CreativePerformanceHistoryRequest.model_validate(arguments)
    try:
        from ..data_retrievers import HistoricalDataRetriever
        retriever = HistoricalDataRetriever(client)
        
        data = await retriever.get_creative_performance_history(
            ad_account_id=request.ad_account_id,
            start_date=request.start_date,
            end_date=request.end_date,
            creative_ids=request.creative_ids,
            include_fatigue_analysis=request.include_fatigue_analysis,
        )
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_creative_performance_history_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def hourly_breakdown_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = HourlyBreakdownRequest.model_validate(arguments)
    try:
        from ..data_retrievers import HistoricalDataRetriever
        retriever = HistoricalDataRetriever(client)
        
        data = await retriever.get_hourly_breakdown(
            entity_id=request.entity_id,
            entity_type=request.entity_type,
            start_date=request.start_date,
            end_date=request.end_date,
            timezone=request.timezone,
        )
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_hourly_breakdown_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def compare_periods_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = ComparePeriodsRequest.model_validate(arguments)
    try:
        from ..data_retrievers import HistoricalDataRetriever
        retriever = HistoricalDataRetriever(client)
        
        data = await retriever.compare_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,
        )
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_compare_periods_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def performance_by_demographics_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = PerformanceByDemographicsRequest.model_validate(arguments)
    try:
        from ..data_retrievers import GranularMetricsRetriever
        retriever = GranularMetricsRetriever(client)
        
        data = await retriever.get_performance_by_demographics(
            entity_id=request.entity_id,
            entity_type=request.entity_type,
            start_date=request.start_date,
            end_date=request.end_date,
            demographics=request.demographics,
            metrics=request.metrics,
        )
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_performance_by_demographics_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def performance_by_device_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = PerformanceByDeviceRequest.model_validate(arguments)
    try:
        from ..data_retrievers import GranularMetricsRetriever
        retriever = GranularMetricsRetriever(client)
        
        data = await retriever.get_performance_by_device(
            entity_id=request.entity_id,
            entity_type=request.entity_type,
            start_date=request.start_date,
            end_date=request.end_date,
            device_types=request.device_types,
            metrics=request.metrics,
        )
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_performance_by_device_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def performance_by_placement_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = PerformanceByPlacementRequest.model_validate(arguments)
    try:
        from ..data_retrievers import GranularMetricsRetriever
        retriever = GranularMetricsRetriever(client)
        
        data = await retriever.get_performance_by_placement(
            entity_id=request.entity_id,
            entity_type=request.entity_type,
            start_date=request.start_date,
            end_date=request.end_date,
            placements=request.placements,
            metrics=request.metrics,
        )
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_performance_by_placement_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def performance_by_time_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = PerformanceByTimeRequest.model_validate(arguments)
    try:
        from ..data_retrievers import GranularMetricsRetriever
        retriever = GranularMetricsRetriever(client)
        
        data = await retriever.get_performance_by_time(
            entity_id=request.entity_id,
            entity_type=request.entity_type,
            start_date=request.start_date,
            end_date=request.end_date,
            interval=request.interval,
            metrics=request.metrics,
        )
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_performance_by_time_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.campaign_performance_history": (
            mcp_types.Tool(
                name="meta.campaign_performance_history",
                description="Get historical campaign performance over time. Returns daily/weekly metrics including spend, ROAS, CPA, and conversions. Use for trend analysis and reporting.",
                inputSchema=_tool_schema(CampaignPerformanceHistoryRequest),
            ),
            partial(campaign_performance_history_handler, client),
        ),
        "meta.spend_trends": (
            mcp_types.Tool(
                name="meta.spend_trends",
                description="Analyze spend trends and forecasts. View historical spend patterns, seasonality, and budget pacing projections. Use for financial planning and budget optimization.",
                inputSchema=_tool_schema(SpendTrendsRequest),
            ),
            partial(spend_trends_handler, client),
        ),
        "meta.audience_performance_history": (
            mcp_types.Tool(
                name="meta.audience_performance_history",
                description="Get historical audience performance by segment. Compare custom audience and lookalike performance over time. Use for audience strategy decisions.",
                inputSchema=_tool_schema(AudiencePerformanceHistoryRequest),
            ),
            partial(audience_performance_history_handler, client),
        ),
        "meta.creative_performance_history": (
            mcp_types.Tool(
                name="meta.creative_performance_history",
                description="Get historical creative performance with fatigue analysis. Track creative wear-out, engagement trends, and refresh timing. Use for creative strategy planning.",
                inputSchema=_tool_schema(CreativePerformanceHistoryRequest),
            ),
            partial(creative_performance_history_handler, client),
        ),
        "meta.hourly_breakdown": (
            mcp_types.Tool(
                name="meta.hourly_breakdown",
                description="Get performance breakdown by hour of day. Identify peak performance hours, optimize dayparting, and schedule adjustments. Use for time-based optimization.",
                inputSchema=_tool_schema(HourlyBreakdownRequest),
            ),
            partial(hourly_breakdown_handler, client),
        ),
        "meta.compare_periods": (
            mcp_types.Tool(
                name="meta.compare_periods",
                description="Compare performance between two time periods (week-over-week, month-over-month). Calculate percentage changes and highlight significant shifts. Use for trend reporting.",
                inputSchema=_tool_schema(ComparePeriodsRequest),
            ),
            partial(compare_periods_handler, client),
        ),
        "meta.performance_by_demographics": (
            mcp_types.Tool(
                name="meta.performance_by_demographics",
                description="Get performance breakdown by age, gender, and demographics. Identify high-performing segments and targeting opportunities. Use for audience insights.",
                inputSchema=_tool_schema(PerformanceByDemographicsRequest),
            ),
            partial(performance_by_demographics_handler, client),
        ),
        "meta.performance_by_device": (
            mcp_types.Tool(
                name="meta.performance_by_device",
                description="Get performance breakdown by device type (mobile, desktop, tablet). Compare conversion rates and CPA across devices. Use for cross-device strategy.",
                inputSchema=_tool_schema(PerformanceByDeviceRequest),
            ),
            partial(performance_by_device_handler, client),
        ),
        "meta.performance_by_placement": (
            mcp_types.Tool(
                name="meta.performance_by_placement",
                description="Get performance breakdown by placement (Feed, Stories, Reels, Audience Network). Identify top placements and optimize allocation. Use for placement strategy.",
                inputSchema=_tool_schema(PerformanceByPlacementRequest),
            ),
            partial(performance_by_placement_handler, client),
        ),
        "meta.performance_by_time": (
            mcp_types.Tool(
                name="meta.performance_by_time",
                description="Get performance over time intervals (hourly, daily, weekly). View metric trends and identify patterns. Use for time-series analysis and reporting.",
                inputSchema=_tool_schema(PerformanceByTimeRequest),
            ),
            partial(performance_by_time_handler, client),
        ),
    }
