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 (
    SimulateBudgetIncreaseRequest,
    SimulateBidChangesRequest,
    SimulateAudienceExpansionRequest,
    SimulateCreativeRefreshRequest,
    SimulateSeasonalPlanningRequest,
    CompareStrategiesRequest,
    ToolResult
)
from .base import ToolHandler, _tool_schema

logger = get_logger(__name__)

async def scenario_budget_increase_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = SimulateBudgetIncreaseRequest.model_validate(arguments)
    try:
        from ..scenario_planning import get_scenario_engine
        engine = get_scenario_engine()
        
        data = await engine.simulate_budget_increase(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_scenario_budget_increase_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def scenario_bid_changes_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = SimulateBidChangesRequest.model_validate(arguments)
    try:
        from ..scenario_planning import get_scenario_engine
        engine = get_scenario_engine()
        
        data = await engine.simulate_bid_changes(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_scenario_bid_changes_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def scenario_audience_expansion_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = SimulateAudienceExpansionRequest.model_validate(arguments)
    try:
        from ..scenario_planning import get_scenario_engine
        engine = get_scenario_engine()
        
        data = await engine.simulate_audience_expansion(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_scenario_audience_expansion_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def scenario_creative_refresh_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = SimulateCreativeRefreshRequest.model_validate(arguments)
    try:
        from ..scenario_planning import get_scenario_engine
        engine = get_scenario_engine()
        
        data = await engine.simulate_creative_refresh(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_scenario_creative_refresh_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def scenario_seasonal_planning_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = SimulateSeasonalPlanningRequest.model_validate(arguments)
    try:
        from ..scenario_planning import get_scenario_engine
        engine = get_scenario_engine()
        
        data = await engine.simulate_seasonal_planning(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_scenario_seasonal_planning_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def scenario_compare_strategies_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = CompareStrategiesRequest.model_validate(arguments)
    try:
        from ..scenario_planning import get_scenario_engine
        engine = get_scenario_engine()
        
        data = await engine.compare_strategies(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_scenario_compare_strategies_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.scenario.budget_increase": (
            mcp_types.Tool(
                name="meta.scenario.budget_increase",
                description="Simulate budget increase scenarios with projected outcomes. Forecast reach, conversions, and diminishing returns. Use for budget planning what-if analysis.",
                inputSchema=_tool_schema(SimulateBudgetIncreaseRequest),
            ),
            partial(scenario_budget_increase_handler, client),
        ),
        "meta.scenario.bid_changes": (
            mcp_types.Tool(
                name="meta.scenario.bid_changes",
                description="Simulate bid change scenarios to predict auction outcomes. Forecast volume, cost, and win rate changes. Use for bid strategy what-if analysis.",
                inputSchema=_tool_schema(SimulateBidChangesRequest),
            ),
            partial(scenario_bid_changes_handler, client),
        ),
        "meta.scenario.audience_expansion": (
            mcp_types.Tool(
                name="meta.scenario.audience_expansion",
                description="Simulate audience expansion impact on reach and CPA. Model lookalike and interest targeting changes. Use for targeting what-if analysis.",
                inputSchema=_tool_schema(SimulateAudienceExpansionRequest),
            ),
            partial(scenario_audience_expansion_handler, client),
        ),
        "meta.scenario.creative_refresh": (
            mcp_types.Tool(
                name="meta.scenario.creative_refresh",
                description="Simulate creative refresh impact on fatigue and engagement. Predict performance improvement from new ads. Use for creative planning.",
                inputSchema=_tool_schema(SimulateCreativeRefreshRequest),
            ),
            partial(scenario_creative_refresh_handler, client),
        ),
        "meta.scenario.seasonal_planning": (
            mcp_types.Tool(
                name="meta.scenario.seasonal_planning",
                description="Simulate seasonal planning for holidays and events. Model budget pacing, CPM changes, and demand forecasts. Use for peak period planning.",
                inputSchema=_tool_schema(SimulateSeasonalPlanningRequest),
            ),
            partial(scenario_seasonal_planning_handler, client),
        ),
        "meta.scenario.compare_strategies": (
            mcp_types.Tool(
                name="meta.scenario.compare_strategies",
                description="Compare multiple strategy scenarios side-by-side. Evaluate budget, bid, and targeting combinations. Use for strategic decision-making.",
                inputSchema=_tool_schema(CompareStrategiesRequest),
            ),
            partial(scenario_compare_strategies_handler, client),
        ),
    }
