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 (
    CrossPlatformJourneyRequest,
    FirstTouchAnalysisRequest,
    LastTouchAnalysisRequest,
    TimeDecayModelRequest,
    PositionBasedModelRequest,
    DataDrivenModelRequest,
    IncrementalityTestRequest,
    CrossDeviceTrackingRequest,
    ToolResult
)
from .base import ToolHandler, _tool_schema

logger = get_logger(__name__)

async def cross_platform_journey_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = CrossPlatformJourneyRequest.model_validate(arguments)
    try:
        from ..attribution_analysis import AttributionAnalysisEngine
        engine = AttributionAnalysisEngine(client)
        
        data = await engine.cross_platform_journey(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_cross_platform_journey_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def first_touch_analysis_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = FirstTouchAnalysisRequest.model_validate(arguments)
    try:
        from ..attribution_analysis import AttributionAnalysisEngine
        engine = AttributionAnalysisEngine(client)
        
        data = await engine.first_touch_analysis(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_first_touch_analysis_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def last_touch_analysis_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = LastTouchAnalysisRequest.model_validate(arguments)
    try:
        from ..attribution_analysis import AttributionAnalysisEngine
        engine = AttributionAnalysisEngine(client)
        
        data = await engine.last_touch_analysis(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_last_touch_analysis_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def time_decay_model_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = TimeDecayModelRequest.model_validate(arguments)
    try:
        from ..attribution_analysis import AttributionAnalysisEngine
        engine = AttributionAnalysisEngine(client)
        
        data = await engine.time_decay_model(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_time_decay_model_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def position_based_model_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = PositionBasedModelRequest.model_validate(arguments)
    try:
        from ..attribution_analysis import AttributionAnalysisEngine
        engine = AttributionAnalysisEngine(client)
        
        data = await engine.position_based_model(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_position_based_model_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def data_driven_model_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = DataDrivenModelRequest.model_validate(arguments)
    try:
        from ..attribution_analysis import AttributionAnalysisEngine
        engine = AttributionAnalysisEngine(client)
        
        data = await engine.data_driven_model(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_data_driven_model_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def incrementality_test_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = IncrementalityTestRequest.model_validate(arguments)
    try:
        from ..attribution_analysis import AttributionAnalysisEngine
        engine = AttributionAnalysisEngine(client)
        
        data = await engine.incrementality_test(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_incrementality_test_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def cross_device_tracking_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = CrossDeviceTrackingRequest.model_validate(arguments)
    try:
        from ..attribution_analysis import AttributionAnalysisEngine
        engine = AttributionAnalysisEngine(client)
        
        data = await engine.cross_device_tracking(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_cross_device_tracking_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.attribution.cross_platform_journey": (
            mcp_types.Tool(
                name="meta.attribution.cross_platform_journey",
                description="Map user journey across Meta platforms (Facebook, Instagram, Messenger, WhatsApp). Track touchpoints to conversion. Use for cross-platform analysis.",
                inputSchema=_tool_schema(CrossPlatformJourneyRequest),
            ),
            partial(cross_platform_journey_handler, client),
        ),
        "meta.attribution.first_touch": (
            mcp_types.Tool(
                name="meta.attribution.first_touch",
                description="First-touch attribution model giving 100% credit to first interaction. Measure awareness and discovery. Use for top-of-funnel analysis.",
                inputSchema=_tool_schema(FirstTouchAnalysisRequest),
            ),
            partial(first_touch_analysis_handler, client),
        ),
        "meta.attribution.last_touch": (
            mcp_types.Tool(
                name="meta.attribution.last_touch",
                description="Last-touch attribution model giving 100% credit to final interaction. Measure conversion drivers. Use for bottom-of-funnel analysis.",
                inputSchema=_tool_schema(LastTouchAnalysisRequest),
            ),
            partial(last_touch_analysis_handler, client),
        ),
        "meta.attribution.time_decay": (
            mcp_types.Tool(
                name="meta.attribution.time_decay",
                description="Time-decay attribution model weighting recent touchpoints higher. Balance recency with full journey. Use for multi-touch analysis.",
                inputSchema=_tool_schema(TimeDecayModelRequest),
            ),
            partial(time_decay_model_handler, client),
        ),
        "meta.attribution.position_based": (
            mcp_types.Tool(
                name="meta.attribution.position_based",
                description="Position-based (U-shaped) attribution giving 40% to first, 40% to last, 20% distributed. Balance awareness and conversion. Use for balanced attribution.",
                inputSchema=_tool_schema(PositionBasedModelRequest),
            ),
            partial(position_based_model_handler, client),
        ),
        "meta.attribution.data_driven": (
            mcp_types.Tool(
                name="meta.attribution.data_driven",
                description="Data-driven ML attribution using algorithmic credit assignment based on actual impact. Most accurate model. Use for advanced attribution.",
                inputSchema=_tool_schema(DataDrivenModelRequest),
            ),
            partial(data_driven_model_handler, client),
        ),
        "meta.attribution.incrementality_test": (
            mcp_types.Tool(
                name="meta.attribution.incrementality_test",
                description="Measure true incremental impact using holdout testing. Determine causal lift from ads. Use for incrementality measurement.",
                inputSchema=_tool_schema(IncrementalityTestRequest),
            ),
            partial(incrementality_test_handler, client),
        ),
        "meta.attribution.cross_device": (
            mcp_types.Tool(
                name="meta.attribution.cross_device",
                description="Cross-device journey attribution tracking users across mobile, desktop, and tablet. Unify fragmented journeys. Use for device attribution.",
                inputSchema=_tool_schema(CrossDeviceTrackingRequest),
            ),
            partial(cross_device_tracking_handler, client),
        ),
    }
