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 (
    PerformanceCohortRequest,
    EfficiencyFrontierRequest,
    CannibalizationRequest,
    TimeDecayRequest,
    IncrementalityRequest,
    ContributionMarginsRequest,
    SaturationPointsRequest,
    ToolResult
)
from .base import ToolHandler, _tool_schema

logger = get_logger(__name__)

async def analyze_performance_cohort_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = PerformanceCohortRequest.model_validate(arguments)
    try:
        from ..analysis_bundles import get_analysis_engine
        engine = get_analysis_engine()
        
        data = await engine.analyze_performance_cohort(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_analyze_performance_cohort_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def analyze_efficiency_frontier_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = EfficiencyFrontierRequest.model_validate(arguments)
    try:
        from ..analysis_bundles import get_analysis_engine
        engine = get_analysis_engine()
        
        data = await engine.analyze_efficiency_frontier(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_analyze_efficiency_frontier_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def analyze_cannibalization_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = CannibalizationRequest.model_validate(arguments)
    try:
        from ..analysis_bundles import get_analysis_engine
        engine = get_analysis_engine()
        
        data = await engine.analyze_cannibalization(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_analyze_cannibalization_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def analyze_time_decay_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = TimeDecayRequest.model_validate(arguments)
    try:
        from ..analysis_bundles import get_analysis_engine
        engine = get_analysis_engine()
        
        data = await engine.analyze_time_decay(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_analyze_time_decay_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def analyze_incrementality_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = IncrementalityRequest.model_validate(arguments)
    try:
        from ..analysis_bundles import get_analysis_engine
        engine = get_analysis_engine()
        
        data = await engine.analyze_incrementality(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_analyze_incrementality_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def analyze_contribution_margins_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = ContributionMarginsRequest.model_validate(arguments)
    try:
        from ..analysis_bundles import get_analysis_engine
        engine = get_analysis_engine()
        
        data = await engine.analyze_contribution_margins(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_analyze_contribution_margins_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def analyze_saturation_points_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = SaturationPointsRequest.model_validate(arguments)
    try:
        from ..analysis_bundles import get_analysis_engine
        engine = get_analysis_engine()
        
        data = await engine.analyze_saturation_points(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_analyze_saturation_points_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.analyze_performance_cohort": (
            mcp_types.Tool(
                name="meta.analyze_performance_cohort",
                description="Analyze performance cohorts to segment campaigns by launch date, spend tier, or performance. Identify patterns across groups. Use for cohort analysis.",
                inputSchema=_tool_schema(PerformanceCohortRequest),
            ),
            partial(analyze_performance_cohort_handler, client),
        ),
        "meta.analyze_efficiency_frontier": (
            mcp_types.Tool(
                name="meta.analyze_efficiency_frontier",
                description="Analyze efficiency frontier to find optimal spend-to-performance ratio. Map diminishing returns curve. Use for budget optimization analysis.",
                inputSchema=_tool_schema(EfficiencyFrontierRequest),
            ),
            partial(analyze_efficiency_frontier_handler, client),
        ),
        "meta.analyze_cannibalization": (
            mcp_types.Tool(
                name="meta.analyze_cannibalization",
                description="Analyze audience cannibalization between campaigns targeting similar audiences. Detect overlap and wasted spend. Use for audience overlap analysis.",
                inputSchema=_tool_schema(CannibalizationRequest),
            ),
            partial(analyze_cannibalization_handler, client),
        ),
        "meta.analyze_time_decay": (
            mcp_types.Tool(
                name="meta.analyze_time_decay",
                description="Analyze time decay attribution to understand how quickly ad impact fades. Model conversion windows. Use for attribution modeling.",
                inputSchema=_tool_schema(TimeDecayRequest),
            ),
            partial(analyze_time_decay_handler, client),
        ),
        "meta.analyze_incrementality": (
            mcp_types.Tool(
                name="meta.analyze_incrementality",
                description="Analyze conversion incrementality to measure true lift from ads. Separate organic from paid conversions. Use for lift measurement.",
                inputSchema=_tool_schema(IncrementalityRequest),
            ),
            partial(analyze_incrementality_handler, client),
        ),
        "meta.analyze_contribution_margins": (
            mcp_types.Tool(
                name="meta.analyze_contribution_margins",
                description="Analyze contribution margins showing profit after ad costs. Calculate true ROI per campaign. Use for profitability analysis.",
                inputSchema=_tool_schema(ContributionMarginsRequest),
            ),
            partial(analyze_contribution_margins_handler, client),
        ),
        "meta.analyze_saturation_points": (
            mcp_types.Tool(
                name="meta.analyze_saturation_points",
                description="Analyze market saturation points where frequency causes diminishing returns. Identify optimal impression caps. Use for saturation analysis.",
                inputSchema=_tool_schema(SaturationPointsRequest),
            ),
            partial(analyze_saturation_points_handler, client),
        ),
    }
