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 (
    CalculateROIRequest,
    CalculateROASRequest,
    CalculateEfficiencyScoreRequest,
    CalculateTrendRequest,
    CalculateVarianceRequest,
    CalculateCorrelationRequest,
    CalculatePacingRequest,
    ToolResult
)
from .base import ToolHandler, _tool_schema

logger = get_logger(__name__)

async def calculate_roi_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = CalculateROIRequest.model_validate(arguments)
    try:
        from ..calculation_tools import get_calculation_engine
        engine = get_calculation_engine()
        
        data = await engine.calculate_roi(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_calculate_roi_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def calculate_roas_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = CalculateROASRequest.model_validate(arguments)
    try:
        from ..calculation_tools import get_calculation_engine
        engine = get_calculation_engine()
        
        data = await engine.calculate_roas(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_calculate_roas_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def calculate_efficiency_score_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = CalculateEfficiencyScoreRequest.model_validate(arguments)
    try:
        from ..calculation_tools import get_calculation_engine
        engine = get_calculation_engine()
        
        data = await engine.calculate_efficiency_score(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_calculate_efficiency_score_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def calculate_trend_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = CalculateTrendRequest.model_validate(arguments)
    try:
        from ..calculation_tools import get_calculation_engine
        engine = get_calculation_engine()
        
        data = await engine.calculate_trend(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_calculate_trend_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def calculate_variance_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = CalculateVarianceRequest.model_validate(arguments)
    try:
        from ..calculation_tools import get_calculation_engine
        engine = get_calculation_engine()
        
        data = await engine.calculate_variance(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_calculate_variance_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def calculate_correlation_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = CalculateCorrelationRequest.model_validate(arguments)
    try:
        from ..calculation_tools import get_calculation_engine
        engine = get_calculation_engine()
        
        data = await engine.calculate_correlation(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_calculate_correlation_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def calculate_pacing_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = CalculatePacingRequest.model_validate(arguments)
    try:
        from ..calculation_tools import get_calculation_engine
        engine = get_calculation_engine()
        
        data = await engine.calculate_pacing(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_calculate_pacing_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.calculate_roi": (
            mcp_types.Tool(
                name="meta.calculate_roi",
                description="Calculate ROI (Return on Investment) for campaigns. Factor in costs and revenue to measure profitability. Use for financial performance analysis.",
                inputSchema=_tool_schema(CalculateROIRequest),
            ),
            partial(calculate_roi_handler, client),
        ),
        "meta.calculate_roas": (
            mcp_types.Tool(
                name="meta.calculate_roas",
                description="Calculate ROAS (Return on Ad Spend) for campaigns. Measure revenue generated per dollar spent. Use for advertising efficiency analysis.",
                inputSchema=_tool_schema(CalculateROASRequest),
            ),
            partial(calculate_roas_handler, client),
        ),
        "meta.calculate_efficiency_score": (
            mcp_types.Tool(
                name="meta.calculate_efficiency_score",
                description="Calculate composite efficiency score across multiple metrics. Compare campaigns on a normalized scale. Use for cross-campaign comparisons.",
                inputSchema=_tool_schema(CalculateEfficiencyScoreRequest),
            ),
            partial(calculate_efficiency_score_handler, client),
        ),
        "meta.calculate_trend": (
            mcp_types.Tool(
                name="meta.calculate_trend",
                description="Calculate trend analysis with direction, velocity, and seasonality. Detect upward/downward patterns. Use for performance trending.",
                inputSchema=_tool_schema(CalculateTrendRequest),
            ),
            partial(calculate_trend_handler, client),
        ),
        "meta.calculate_variance": (
            mcp_types.Tool(
                name="meta.calculate_variance",
                description="Calculate variance between actual vs expected performance. Identify over/under delivery. Use for variance analysis.",
                inputSchema=_tool_schema(CalculateVarianceRequest),
            ),
            partial(calculate_variance_handler, client),
        ),
        "meta.calculate_correlation": (
            mcp_types.Tool(
                name="meta.calculate_correlation",
                description="Calculate correlation between metrics to find relationships. Identify leading indicators. Use for metric correlation analysis.",
                inputSchema=_tool_schema(CalculateCorrelationRequest),
            ),
            partial(calculate_correlation_handler, client),
        ),
        "meta.calculate_pacing": (
            mcp_types.Tool(
                name="meta.calculate_pacing",
                description="Calculate budget pacing against targets. Track daily/weekly spend vs plan. Use for budget pacing monitoring.",
                inputSchema=_tool_schema(CalculatePacingRequest),
            ),
            partial(calculate_pacing_handler, client),
        ),
    }
