"""
Tool Executor - Executes tools with connector integration
"""
from typing import Any, Dict, List, Optional
from app.tools.base import Tool, ToolResult
from app.tools.registry import tool_registry
import logging
import json

logger = logging.getLogger(__name__)


class ToolExecutor:
    """
    Executes tools requested by the AI agent.

    The executor:
    1. Validates tool requests
    2. Gets the appropriate connector for the client
    3. Executes the tool
    4. Returns formatted results
    """

    def __init__(self, connector_manager=None):
        """
        Initialize the tool executor.

        Args:
            connector_manager: Manager for getting client connectors
        """
        # Lazy import to avoid circular dependency
        if connector_manager is None:
            from app.connectors.manager import connector_manager as cm
            self.connector_manager = cm
        else:
            self.connector_manager = connector_manager
        self.registry = tool_registry

    async def execute(
        self,
        tool_name: str,
        params: Dict[str, Any],
        context: Dict[str, Any]
    ) -> ToolResult:
        """
        Execute a tool by name.

        Args:
            tool_name: Name of the tool to execute
            params: Parameters for the tool
            context: Execution context (client_id, user_id, conversation_id, etc.)

        Returns:
            ToolResult with the outcome
        """
        # Get the tool
        tool = self.registry.get(tool_name)
        if not tool:
            logger.error(f"Tool not found: {tool_name}")
            return ToolResult.error_result(f"Tool '{tool_name}' not found")

        # Validate parameters
        validation_error = tool.validate_params(params)
        if validation_error:
            logger.warning(f"Tool validation failed: {validation_error}")
            return ToolResult.error_result(validation_error)

        # Get the connector for this client
        client_id = context.get("client_id")
        connector = await self._get_connector(client_id, context)

        if not connector:
            return ToolResult.error_result("No connector configured for this client")

        # Execute the tool
        try:
            logger.info(f"Executing tool: {tool_name} with params: {params}")
            result = await tool.execute(
                connector=connector,
                params=params,
                context=context
            )
            logger.info(f"Tool {tool_name} executed: success={result.success}")
            return result

        except Exception as e:
            logger.exception(f"Tool execution error: {tool_name}")
            return ToolResult.error_result(f"Tool execution failed: {str(e)}")

    async def execute_multiple(
        self,
        tool_calls: List[Dict[str, Any]],
        context: Dict[str, Any]
    ) -> List[Dict[str, Any]]:
        """
        Execute multiple tool calls (for parallel tool execution).

        Args:
            tool_calls: List of {tool_name, params} dicts
            context: Execution context

        Returns:
            List of results with tool names
        """
        results = []
        for call in tool_calls:
            tool_name = call.get("tool_name") or call.get("name")
            params = call.get("params") or call.get("arguments", {})

            # Parse arguments if they're a string (from AI model)
            if isinstance(params, str):
                try:
                    params = json.loads(params)
                except json.JSONDecodeError:
                    params = {}

            result = await self.execute(tool_name, params, context)
            results.append({
                "tool_name": tool_name,
                "result": result.model_dump()
            })

        return results

    async def _get_connector(
        self,
        client_id: Optional[int],
        context: Dict[str, Any]
    ) -> Any:
        """
        Get the appropriate connector for a client.

        Args:
            client_id: Client ID
            context: Additional context

        Returns:
            Connector instance or None
        """
        if not client_id:
            # Return a demo/mock connector for testing
            return MockConnector()

        if self.connector_manager:
            connector = await self.connector_manager.get_connector(client_id)
            if connector:
                return connector

        # Fallback to mock connector if no real connector configured
        logger.info(f"Using mock connector for client {client_id} (no connector configured)")
        return MockConnector()

    def get_available_tools(
        self,
        agent_type: str = "general"
    ) -> List[Dict[str, Any]]:
        """
        Get function schemas for available tools.

        Args:
            agent_type: Type of agent requesting tools

        Returns:
            List of function schemas for AI model
        """
        return self.registry.get_function_schemas(agent_type)

    def requires_confirmation(self, tool_name: str) -> bool:
        """
        Check if a tool requires user confirmation.

        Args:
            tool_name: Name of the tool

        Returns:
            True if confirmation is required
        """
        tool = self.registry.get(tool_name)
        return tool.requires_confirmation if tool else False


class MockConnector:
    """
    Mock connector for testing and development.
    Returns sample data for all operations.
    """

    async def get_sales(self, **kwargs) -> Dict[str, Any]:
        period = kwargs.get("period", "today")
        return {
            "period": period,
            "total_revenue": 125000.00,
            "order_count": 45,
            "average_order_value": 2777.78,
            "currency": "INR"
        }

    async def get_sales_comparison(self, **kwargs) -> Dict[str, Any]:
        return {
            "current_period": {
                "total_revenue": 125000.00,
                "order_count": 45
            },
            "previous_period": {
                "total_revenue": 98000.00,
                "order_count": 38
            },
            "growth": {
                "revenue_percent": 27.55,
                "orders_percent": 18.42
            }
        }

    async def get_top_products(self, **kwargs) -> Dict[str, Any]:
        return {
            "products": [
                {"id": "1", "title": "Premium Widget", "revenue": 45000, "quantity": 150},
                {"id": "2", "title": "Standard Widget", "revenue": 32000, "quantity": 200},
                {"id": "3", "title": "Basic Widget", "revenue": 18000, "quantity": 300},
            ]
        }

    async def get_revenue_breakdown(self, **kwargs) -> Dict[str, Any]:
        return {
            "breakdown": [
                {"category": "Electronics", "revenue": 65000, "percentage": 52},
                {"category": "Accessories", "revenue": 35000, "percentage": 28},
                {"category": "Services", "revenue": 25000, "percentage": 20},
            ]
        }

    async def get_orders(self, **kwargs) -> Dict[str, Any]:
        return {
            "orders": [
                {"id": "ORD-001", "status": "delivered", "total": 5999, "customer": "John Doe"},
                {"id": "ORD-002", "status": "shipped", "total": 3499, "customer": "Jane Smith"},
                {"id": "ORD-003", "status": "processing", "total": 7899, "customer": "Bob Wilson"},
            ],
            "total_count": 3
        }

    async def get_order_details(self, **kwargs) -> Dict[str, Any]:
        order_id = kwargs.get("order_id", "ORD-001")
        return {
            "id": order_id,
            "status": "delivered",
            "total": 5999,
            "subtotal": 5499,
            "tax": 500,
            "customer": {
                "name": "John Doe",
                "email": "john@example.com",
                "phone": "+91 98765 43210"
            },
            "items": [
                {"product": "Premium Widget", "quantity": 2, "price": 2749.50}
            ],
            "shipping": {
                "address": "123 Main St, Mumbai",
                "method": "Express",
                "tracking": "TRK123456"
            },
            "created_at": "2026-10-01T10:30:00Z"
        }

    async def get_order_status(self, **kwargs) -> Dict[str, Any]:
        order_id = kwargs.get("order_id", "ORD-001")
        return {
            "order_id": order_id,
            "status": "delivered",
            "tracking_number": "TRK123456",
            "estimated_delivery": "2026-10-05",
            "timeline": [
                {"status": "ordered", "date": "2026-10-01T10:30:00Z"},
                {"status": "processing", "date": "2026-10-01T14:00:00Z"},
                {"status": "shipped", "date": "2026-10-02T09:00:00Z"},
                {"status": "delivered", "date": "2026-10-04T16:30:00Z"},
            ]
        }

    async def create_refund(self, **kwargs) -> Dict[str, Any]:
        return {
            "refund_id": "REF-001",
            "order_id": kwargs.get("order_id"),
            "amount": kwargs.get("amount", 5999),
            "status": "processed",
            "reason": kwargs.get("reason"),
            "created_at": "2026-10-06T12:00:00Z"
        }

    async def update_order_status(self, **kwargs) -> Dict[str, Any]:
        return {
            "order_id": kwargs.get("order_id"),
            "status": kwargs.get("status"),
            "updated_at": "2026-10-06T12:00:00Z"
        }

    async def get_products(self, **kwargs) -> Dict[str, Any]:
        return {
            "products": [
                {"id": "1", "title": "Premium Widget", "price": 2999, "stock": 150},
                {"id": "2", "title": "Standard Widget", "price": 1999, "stock": 200},
                {"id": "3", "title": "Basic Widget", "price": 999, "stock": 5},
            ]
        }

    async def get_product_details(self, **kwargs) -> Dict[str, Any]:
        return {
            "id": kwargs.get("product_id", "1"),
            "title": "Premium Widget",
            "description": "High-quality premium widget",
            "price": 2999,
            "compare_at_price": 3499,
            "stock": 150,
            "sku": "PREM-001",
            "category": "Electronics",
            "variants": [
                {"id": "v1", "title": "Red", "stock": 50},
                {"id": "v2", "title": "Blue", "stock": 100}
            ]
        }

    async def search_products(self, **kwargs) -> Dict[str, Any]:
        query = kwargs.get("query", "")
        return {
            "products": [
                {"id": "1", "title": f"Premium {query}", "price": 2999, "stock": 150},
            ],
            "query": query
        }

    async def get_low_stock_products(self, **kwargs) -> Dict[str, Any]:
        return {
            "products": [
                {"id": "3", "title": "Basic Widget", "stock": 5, "threshold": 10},
                {"id": "5", "title": "Mini Widget", "stock": 0, "threshold": 10},
            ]
        }

    async def get_inventory(self, **kwargs) -> Dict[str, Any]:
        return {
            "inventory": [
                {"product_id": "1", "title": "Premium Widget", "quantity": 150, "location": "Warehouse A"},
                {"product_id": "2", "title": "Standard Widget", "quantity": 200, "location": "Warehouse A"},
            ]
        }

    async def get_inventory_alerts(self, **kwargs) -> Dict[str, Any]:
        return {
            "alerts": [
                {"type": "low_stock", "product_id": "3", "title": "Basic Widget", "current": 5, "threshold": 10},
                {"type": "out_of_stock", "product_id": "5", "title": "Mini Widget", "current": 0},
            ]
        }

    async def update_inventory(self, **kwargs) -> Dict[str, Any]:
        return {
            "product_id": kwargs.get("product_id"),
            "new_quantity": kwargs.get("quantity"),
            "updated_at": "2026-10-06T12:00:00Z"
        }

    async def get_customers(self, **kwargs) -> Dict[str, Any]:
        return {
            "customers": [
                {"id": "1", "name": "John Doe", "email": "john@example.com", "orders": 12, "total_spent": 45000},
                {"id": "2", "name": "Jane Smith", "email": "jane@example.com", "orders": 8, "total_spent": 32000},
            ]
        }

    async def get_customer_details(self, **kwargs) -> Dict[str, Any]:
        return {
            "id": kwargs.get("customer_id", "1"),
            "name": "John Doe",
            "email": "john@example.com",
            "phone": "+91 98765 43210",
            "total_orders": 12,
            "total_spent": 45000,
            "average_order": 3750,
            "first_order": "2025-01-15",
            "last_order": "2026-10-01",
            "recent_orders": [
                {"id": "ORD-001", "date": "2026-10-01", "total": 5999}
            ]
        }

    async def get_top_customers(self, **kwargs) -> Dict[str, Any]:
        return {
            "customers": [
                {"id": "1", "name": "John Doe", "revenue": 45000, "orders": 12},
                {"id": "2", "name": "Jane Smith", "revenue": 32000, "orders": 8},
                {"id": "3", "name": "Bob Wilson", "revenue": 28000, "orders": 15},
            ]
        }

    async def search_customers(self, **kwargs) -> Dict[str, Any]:
        query = kwargs.get("query", "")
        return {
            "customers": [
                {"id": "1", "name": "John Doe", "email": "john@example.com"},
            ],
            "query": query
        }


# Singleton executor instance
tool_executor = ToolExecutor()
