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 (
    SetBidStrategyRequest,
    SetBidCapRequest,
    SetTargetCostRequest,
    GetAuctionInsightsRequest,
    SimulateBidChangeRequest,
    ToolResult
)
from .base import ToolHandler, _tool_schema

logger = get_logger(__name__)

async def set_bid_strategy_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = SetBidStrategyRequest.model_validate(arguments)
    try:
        from ..bid_manager import BidManager
        manager = BidManager(client)
        
        data = await manager.set_bid_strategy(
            entity_id=request.entity_id,
            entity_type=request.entity_type,
            bid_strategy=request.bid_strategy,
            bid_amount=request.bid_amount,
        )
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_set_bid_strategy_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def set_bid_cap_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = SetBidCapRequest.model_validate(arguments)
    try:
        from ..bid_manager import BidManager
        manager = BidManager(client)
        
        data = await manager.set_bid_cap(
            entity_id=request.entity_id,
            entity_type=request.entity_type,
            bid_cap=request.bid_cap,
            validate_limits=request.validate_limits,
        )
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_set_bid_cap_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def set_target_cost_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = SetTargetCostRequest.model_validate(arguments)
    try:
        from ..bid_manager import BidManager
        manager = BidManager(client)
        
        data = await manager.set_target_cost(
            entity_id=request.entity_id,
            entity_type=request.entity_type,
            target_cost=request.target_cost,
            validate_limits=request.validate_limits,
        )
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_set_target_cost_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def get_auction_insights_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = GetAuctionInsightsRequest.model_validate(arguments)
    try:
        from ..bid_manager import BidManager
        manager = BidManager(client)
        
        data = await manager.get_auction_insights(
            entity_id=request.entity_id,
            entity_type=request.entity_type,
            start_date=request.start_date,
            end_date=request.end_date,
            include_competitors=request.include_competitors,
        )
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_get_auction_insights_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def simulate_bid_change_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = SimulateBidChangeRequest.model_validate(arguments)
    try:
        from ..bid_manager import BidManager
        manager = BidManager(client)
        
        data = await manager.simulate_bid_change(
            entity_id=request.entity_id,
            entity_type=request.entity_type,
            new_bid_strategy=request.new_bid_strategy,
            new_bid_amount=request.new_bid_amount,
            simulation_period=request.simulation_period,
        )
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_simulate_bid_change_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.set_bid_strategy": (
            mcp_types.Tool(
                name="meta.set_bid_strategy",
                description="Set bid strategy for campaigns or ad sets. Choose from Lowest Cost, Cost Cap, Bid Cap, or ROAS goal strategies. Use for auction optimization and cost control.",
                inputSchema=_tool_schema(SetBidStrategyRequest),
            ),
            partial(set_bid_strategy_handler, client),
        ),
        "meta.set_bid_cap": (
            mcp_types.Tool(
                name="meta.set_bid_cap",
                description="Set maximum bid cap amount for cost control. Prevents overpaying in competitive auctions. Use for strict CPA/CPM limits and budget protection.",
                inputSchema=_tool_schema(SetBidCapRequest),
            ),
            partial(set_bid_cap_handler, client),
        ),
        "meta.set_target_cost": (
            mcp_types.Tool(
                name="meta.set_target_cost",
                description="Set target CPA or cost per result goal. Algorithm optimizes to achieve average cost target. Use for predictable cost-per-conversion management.",
                inputSchema=_tool_schema(SetTargetCostRequest),
            ),
            partial(set_target_cost_handler, client),
        ),
        "meta.get_auction_insights": (
            mcp_types.Tool(
                name="meta.get_auction_insights",
                description="Get auction insights including win rate, competition overlap, and share of impressions. Analyze competitive landscape. Use for bid strategy planning.",
                inputSchema=_tool_schema(GetAuctionInsightsRequest),
            ),
            partial(get_auction_insights_handler, client),
        ),
        "meta.simulate_bid_change": (
            mcp_types.Tool(
                name="meta.simulate_bid_change",
                description="Simulate bid change impact before applying. Forecast volume, cost, and ROAS effects of bid adjustments. Use for risk-free bid optimization.",
                inputSchema=_tool_schema(SimulateBidChangeRequest),
            ),
            partial(simulate_bid_change_handler, client),
        ),
    }
