from typing import Any, Dict, Tuple
from functools import partial

from mcp import types as mcp_types

from ..errors import MetaApiError
from ..logging import get_logger
from ..meta_client import MetaClient
from ..schemas import (
    AnalyzeConversionFunnelRequest,
    OptimizeLandingPagesRequest,
    TrackPostClickBehaviorRequest,
    AnalyzeConversionPathsRequest,
    DetectCartAbandonmentRequest,
    OptimizeCheckoutFlowRequest,
    AnalyzeFormCompletionRequest,
    CompareMobileDesktopConversionRequest,
    OptimizeConversionWindowsRequest,
    AnalyzeMicroConversionsRequest,
    CheckFlaggedConversionRequest,
    ToolResult
)
from .base import ToolHandler, _tool_schema

logger = get_logger(__name__)

async def analyze_conversion_funnel_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = AnalyzeConversionFunnelRequest.model_validate(arguments)
    try:
        from ..conversion_optimization import ConversionOptimizationEngine
        engine = ConversionOptimizationEngine(client)
        
        data = await engine.analyze_conversion_funnel(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_analyze_conversion_funnel_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def optimize_landing_pages_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = OptimizeLandingPagesRequest.model_validate(arguments)
    try:
        from ..conversion_optimization import ConversionOptimizationEngine
        engine = ConversionOptimizationEngine(client)
        
        data = await engine.optimize_landing_pages(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_optimize_landing_pages_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def track_post_click_behavior_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = TrackPostClickBehaviorRequest.model_validate(arguments)
    try:
        from ..conversion_optimization import ConversionOptimizationEngine
        engine = ConversionOptimizationEngine(client)
        
        data = await engine.track_post_click_behavior(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_track_post_click_behavior_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def analyze_conversion_paths_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = AnalyzeConversionPathsRequest.model_validate(arguments)
    try:
        from ..conversion_optimization import ConversionOptimizationEngine
        engine = ConversionOptimizationEngine(client)
        
        data = await engine.analyze_conversion_paths(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_analyze_conversion_paths_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def detect_cart_abandonment_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = DetectCartAbandonmentRequest.model_validate(arguments)
    try:
        from ..conversion_optimization import ConversionOptimizationEngine
        engine = ConversionOptimizationEngine(client)
        
        data = await engine.detect_cart_abandonment(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_detect_cart_abandonment_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def optimize_checkout_flow_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = OptimizeCheckoutFlowRequest.model_validate(arguments)
    try:
        from ..conversion_optimization import ConversionOptimizationEngine
        engine = ConversionOptimizationEngine(client)
        
        data = await engine.optimize_checkout_flow(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_optimize_checkout_flow_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def analyze_form_completion_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = AnalyzeFormCompletionRequest.model_validate(arguments)
    try:
        from ..conversion_optimization import ConversionOptimizationEngine
        engine = ConversionOptimizationEngine(client)
        
        data = await engine.analyze_form_completion(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_analyze_form_completion_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def compare_mobile_desktop_conversion_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = CompareMobileDesktopConversionRequest.model_validate(arguments)
    try:
        from ..conversion_optimization import ConversionOptimizationEngine
        engine = ConversionOptimizationEngine(client)
        
        data = await engine.compare_mobile_desktop_conversion(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_compare_mobile_desktop_conversion_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def optimize_conversion_windows_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = OptimizeConversionWindowsRequest.model_validate(arguments)
    try:
        from ..conversion_optimization import ConversionOptimizationEngine
        engine = ConversionOptimizationEngine(client)
        
        data = await engine.optimize_conversion_windows(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_optimize_conversion_windows_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def analyze_micro_conversions_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = AnalyzeMicroConversionsRequest.model_validate(arguments)
    try:
        from ..conversion_optimization import ConversionOptimizationEngine
        engine = ConversionOptimizationEngine(client)
        
        data = await engine.analyze_micro_conversions(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_analyze_micro_conversions_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})


async def check_flagged_conversion_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    """v24.0+ Check if a custom conversion is flagged before update operations.
    
    Flagged custom conversions will fail on update in v24.0+. Use this tool
    to check status before attempting any modifications.
    """
    request = CheckFlaggedConversionRequest.model_validate(arguments)
    try:
        # Fetch conversion with flagged status fields
        params = {
            "fields": ",".join(request.fields),
        }
        
        response = await client.get(
            request.custom_conversion_id,
            params=params,
        )
        
        # Determine if conversion is flagged
        is_flagged = response.get("is_flagged", False)
        
        result = {
            "custom_conversion_id": request.custom_conversion_id,
            "name": response.get("name", "Unknown"),
            "is_flagged": is_flagged,
            "flagged_reason": response.get("flagged_reason"),
            "can_update": not is_flagged,
            "resolution_url": "https://www.facebook.com/business/help/2455915321411996",
            "v24_note": "v24.0+: Updating flagged custom conversions will fail. Resolve flagging before update."
        }
        
        if is_flagged:
            result["resolution_steps"] = [
                "1. Go to Events Manager in Meta Ads Manager",
                "2. Find the flagged custom conversion",
                "3. Review the flagged reason",
                "4. Follow the resolution steps at the resolution_url",
                "5. Once resolved, retry the update operation"
            ]
        
        return ToolResult(ok=True, data=result)
    except MetaApiError as exc:
        logger.error("tool_check_flagged_conversion_failed", **exc.to_dict())
        return ToolResult(ok=False, error=exc.to_dict())


def get_tools(client: MetaClient) -> Dict[str, Tuple[mcp_types.Tool, ToolHandler]]:
    return {
        "meta.conversion.analyze_funnel": (
            mcp_types.Tool(
                name="meta.conversion.analyze_funnel",
                description="Analyze conversion funnel from impression to purchase. Identify drop-off points, calculate stage-by-stage conversion rates, and find optimization opportunities. Use for funnel diagnostics.",
                inputSchema=_tool_schema(AnalyzeConversionFunnelRequest),
            ),
            partial(analyze_conversion_funnel_handler, client),
        ),
        "meta.conversion.optimize_landing_pages": (
            mcp_types.Tool(
                name="meta.conversion.optimize_landing_pages",
                description="Optimize landing page performance by analyzing bounce rates, time on page, and conversion correlation. Identifies high and low performing landing pages. Use for CRO improvements.",
                inputSchema=_tool_schema(OptimizeLandingPagesRequest),
            ),
            partial(optimize_landing_pages_handler, client),
        ),
        "meta.conversion.track_post_click": (
            mcp_types.Tool(
                name="meta.conversion.track_post_click",
                description="Track post-click user behavior including page views, scroll depth, and engagement. Analyze user journey from ad click to conversion. Use for behavior understanding.",
                inputSchema=_tool_schema(TrackPostClickBehaviorRequest),
            ),
            partial(track_post_click_behavior_handler, client),
        ),
        "meta.conversion.analyze_paths": (
            mcp_types.Tool(
                name="meta.conversion.analyze_paths",
                description="Analyze multi-touch conversion paths to understand touchpoint sequences. Identifies most common paths to conversion and attribution patterns. Use for journey mapping.",
                inputSchema=_tool_schema(AnalyzeConversionPathsRequest),
            ),
            partial(analyze_conversion_paths_handler, client),
        ),
        "meta.conversion.detect_cart_abandonment": (
            mcp_types.Tool(
                name="meta.conversion.detect_cart_abandonment",
                description="Detect cart abandonment patterns by analyzing add-to-cart to purchase drop-off. Identifies abandonment timing, value, and recovery opportunities. Use for ecommerce optimization.",
                inputSchema=_tool_schema(DetectCartAbandonmentRequest),
            ),
            partial(detect_cart_abandonment_handler, client),
        ),
        "meta.conversion.optimize_checkout": (
            mcp_types.Tool(
                name="meta.conversion.optimize_checkout",
                description="Optimize checkout flow by analyzing step completion, payment method performance, and friction points. Reduces checkout abandonment. Use for purchase rate improvement.",
                inputSchema=_tool_schema(OptimizeCheckoutFlowRequest),
            ),
            partial(optimize_checkout_flow_handler, client),
        ),
        "meta.conversion.analyze_forms": (
            mcp_types.Tool(
                name="meta.conversion.analyze_forms",
                description="Analyze lead form completion rates and field-level drop-off. Identifies problematic form fields and optimal form length. Use for lead gen CRO.",
                inputSchema=_tool_schema(AnalyzeFormCompletionRequest),
            ),
            partial(analyze_form_completion_handler, client),
        ),
        "meta.conversion.compare_devices": (
            mcp_types.Tool(
                name="meta.conversion.compare_devices",
                description="Compare mobile vs desktop conversion rates and behavior. Analyze device-specific conversion barriers and optimization opportunities. Use for cross-device strategy.",
                inputSchema=_tool_schema(CompareMobileDesktopConversionRequest),
            ),
            partial(compare_mobile_desktop_conversion_handler, client),
        ),
        "meta.conversion.optimize_windows": (
            mcp_types.Tool(
                name="meta.conversion.optimize_windows",
                description="Optimize attribution windows by analyzing conversion lag and optimal lookback periods. Compare 1-day, 7-day, and 28-day click attribution. Use for measurement accuracy.",
                inputSchema=_tool_schema(OptimizeConversionWindowsRequest),
            ),
            partial(optimize_conversion_windows_handler, client),
        ),
        "meta.conversion.analyze_micro_conversions": (
            mcp_types.Tool(
                name="meta.conversion.analyze_micro_conversions",
                description="Analyze micro-conversions like newsletter signups, content downloads, and video views. Correlate micro-events with macro-conversions. Use for full-funnel measurement.",
                inputSchema=_tool_schema(AnalyzeMicroConversionsRequest),
            ),
            partial(analyze_micro_conversions_handler, client),
        ),
        "meta.conversion.check_flagged": (
            mcp_types.Tool(
                name="meta.conversion.check_flagged",
                description="[v24.0+] Check if custom conversion is flagged before updating. Returns flagged status and resolution steps. Required in v24.0 as flagged conversions fail on update.",
                inputSchema=_tool_schema(CheckFlaggedConversionRequest),
            ),
            partial(check_flagged_conversion_handler, client),
        ),
    }

