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 (
    PredictBudgetOutcomeRequest,
    PredictCreativeLifespanRequest,
    PredictOptimalTimingRequest,
    PredictAudienceExpansionRequest,
    PredictSeasonalityRequest,
    PredictCompetitivePressureRequest,
    ToolResult
)
from .base import ToolHandler, _tool_schema

logger = get_logger(__name__)

async def predict_budget_outcome_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = PredictBudgetOutcomeRequest.model_validate(arguments)
    try:
        from ..predictive_tools import get_predictive_engine
        engine = get_predictive_engine()
        
        data = await engine.predict_budget_outcome(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_predict_budget_outcome_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def predict_creative_lifespan_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = PredictCreativeLifespanRequest.model_validate(arguments)
    try:
        from ..predictive_tools import get_predictive_engine
        engine = get_predictive_engine()
        
        data = await engine.predict_creative_lifespan(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_predict_creative_lifespan_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def predict_optimal_timing_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = PredictOptimalTimingRequest.model_validate(arguments)
    try:
        from ..predictive_tools import get_predictive_engine
        engine = get_predictive_engine()
        
        data = await engine.predict_optimal_timing(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_predict_optimal_timing_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def predict_audience_expansion_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = PredictAudienceExpansionRequest.model_validate(arguments)
    try:
        from ..predictive_tools import get_predictive_engine
        engine = get_predictive_engine()
        
        data = await engine.predict_audience_expansion_impact(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_predict_audience_expansion_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def predict_seasonality_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = PredictSeasonalityRequest.model_validate(arguments)
    try:
        from ..predictive_tools import get_predictive_engine
        engine = get_predictive_engine()
        
        data = await engine.predict_seasonality_adjustment(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_predict_seasonality_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def predict_competitive_pressure_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = PredictCompetitivePressureRequest.model_validate(arguments)
    try:
        from ..predictive_tools import get_predictive_engine
        engine = get_predictive_engine()
        
        data = await engine.predict_competitive_pressure(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_predict_competitive_pressure_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.predict_budget_outcome": (
            mcp_types.Tool(
                name="meta.predict_budget_outcome",
                description="Predict budget change outcomes using ML models. Forecast spend, conversions, ROAS, and CPA impact of budget adjustments. Use for budget planning decisions.",
                inputSchema=_tool_schema(PredictBudgetOutcomeRequest),
            ),
            partial(predict_budget_outcome_handler, client),
        ),
        "meta.predict_creative_lifespan": (
            mcp_types.Tool(
                name="meta.predict_creative_lifespan",
                description="Predict creative lifespan before fatigue sets in. Uses frequency and engagement decay patterns. Use for creative refresh scheduling.",
                inputSchema=_tool_schema(PredictCreativeLifespanRequest),
            ),
            partial(predict_creative_lifespan_handler, client),
        ),
        "meta.predict_optimal_timing": (
            mcp_types.Tool(
                name="meta.predict_optimal_timing",
                description="Predict optimal timing for campaign launches and changes. Factors in seasonality, competition, and audience behavior. Use for campaign scheduling.",
                inputSchema=_tool_schema(PredictOptimalTimingRequest),
            ),
            partial(predict_optimal_timing_handler, client),
        ),
        "meta.predict_audience_expansion": (
            mcp_types.Tool(
                name="meta.predict_audience_expansion",
                description="Predict audience expansion impact on reach, CPA, and conversion rates. Forecasts lookalike and interest expansion effects. Use for audience strategy.",
                inputSchema=_tool_schema(PredictAudienceExpansionRequest),
            ),
            partial(predict_audience_expansion_handler, client),
        ),
        "meta.predict_seasonality": (
            mcp_types.Tool(
                name="meta.predict_seasonality",
                description="Predict seasonality adjustments for upcoming periods. Identifies holiday, weekend, and monthly patterns. Use for budget and bid planning.",
                inputSchema=_tool_schema(PredictSeasonalityRequest),
            ),
            partial(predict_seasonality_handler, client),
        ),
        "meta.predict_competitive_pressure": (
            mcp_types.Tool(
                name="meta.predict_competitive_pressure",
                description="Predict competitive pressure and CPM trends. Forecasts auction intensity changes. Use for bid strategy and timing decisions.",
                inputSchema=_tool_schema(PredictCompetitivePressureRequest),
            ),
            partial(predict_competitive_pressure_handler, client),
        ),
    }
