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 (
    CompareBrandsRequest,
    IdentifyOutliersRequest,
    AllocateBudgetAcrossBrandsRequest,
    BenchmarkByIndustryRequest,
    HealthScorecardRequest,
    ToolResult
)
from .base import ToolHandler, _tool_schema

logger = get_logger(__name__)

async def compare_brands_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = CompareBrandsRequest.model_validate(arguments)
    try:
        from ..portfolio_management import PortfolioManagementEngine
        engine = PortfolioManagementEngine(client)
        
        data = await engine.compare_brands(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_portfolio_compare_brands_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def identify_outliers_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = IdentifyOutliersRequest.model_validate(arguments)
    try:
        from ..portfolio_management import PortfolioManagementEngine
        engine = PortfolioManagementEngine(client)
        
        data = await engine.identify_outliers(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_portfolio_identify_outliers_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def allocate_budget_across_brands_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = AllocateBudgetAcrossBrandsRequest.model_validate(arguments)
    try:
        from ..portfolio_management import PortfolioManagementEngine
        engine = PortfolioManagementEngine(client)
        
        data = await engine.allocate_budget_across_brands(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_portfolio_allocate_budget_across_brands_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def benchmark_by_industry_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = BenchmarkByIndustryRequest.model_validate(arguments)
    try:
        from ..portfolio_management import PortfolioManagementEngine
        engine = PortfolioManagementEngine(client)
        
        data = await engine.benchmark_by_industry(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_portfolio_benchmark_by_industry_failed", error=str(exc))
        return ToolResult(ok=False, error={"message": str(exc)})

async def health_scorecard_handler(client: MetaClient, arguments: Dict[str, Any]) -> ToolResult:
    request = HealthScorecardRequest.model_validate(arguments)
    try:
        from ..portfolio_management import PortfolioManagementEngine
        engine = PortfolioManagementEngine(client)
        
        data = await engine.health_scorecard(request)
        
        return ToolResult(ok=True, data=data)
    except Exception as exc:
        logger.error("tool_portfolio_health_scorecard_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.portfolio.compare_brands": (
            mcp_types.Tool(
                name="meta.portfolio.compare_brands",
                description="Compare multiple brands side-by-side across key metrics. Rank brands by ROAS, spend efficiency, and growth. Use for multi-brand portfolio analysis.",
                inputSchema=_tool_schema(CompareBrandsRequest),
            ),
            partial(compare_brands_handler, client),
        ),
        "meta.portfolio.identify_outliers": (
            mcp_types.Tool(
                name="meta.portfolio.identify_outliers",
                description="Identify outlier brands performing significantly above or below average. Statistical anomaly detection. Use for portfolio optimization.",
                inputSchema=_tool_schema(IdentifyOutliersRequest),
            ),
            partial(identify_outliers_handler, client),
        ),
        "meta.portfolio.allocate_budget_across_brands": (
            mcp_types.Tool(
                name="meta.portfolio.allocate_budget_across_brands",
                description="Allocate total budget optimally across multiple brands. Uses marginal ROAS to maximize portfolio returns. Use for enterprise budget planning.",
                inputSchema=_tool_schema(AllocateBudgetAcrossBrandsRequest),
            ),
            partial(allocate_budget_across_brands_handler, client),
        ),
        "meta.portfolio.benchmark_by_industry": (
            mcp_types.Tool(
                name="meta.portfolio.benchmark_by_industry",
                description="Benchmark brands against industry standards. Compare CPM, CTR, and ROAS to vertical averages. Use for competitive positioning.",
                inputSchema=_tool_schema(BenchmarkByIndustryRequest),
            ),
            partial(benchmark_by_industry_handler, client),
        ),
        "meta.portfolio.health_scorecard": (
            mcp_types.Tool(
                name="meta.portfolio.health_scorecard",
                description="Generate portfolio health scorecard with grades for each brand. Aggregates performance, efficiency, and growth scores. Use for executive reporting.",
                inputSchema=_tool_schema(HealthScorecardRequest),
            ),
            partial(health_scorecard_handler, client),
        ),
    }
