import logging
import asyncio
from abc import ABC, abstractmethod
from typing import List

from xulcan.kernel.interfaces import ToolExecutor
from xulcan.protocol.tools import ToolCall
from xulcan.protocol.message import ToolMessage

logger = logging.getLogger(__name__)

class BaseToolExecutor(ToolExecutor, ABC):
    
    @abstractmethod
    async def execute(self, call: ToolCall) -> ToolMessage:
        pass

    async def execute_batch(self, calls: List[ToolCall]) -> List[ToolMessage]:
        """Default parallel execution logic using asyncio.gather."""
        
        async def safe_execute(call: ToolCall) -> ToolMessage:
            try:
                return await self.execute(call)
            except Exception as e:
                logger.error(f"Tool {call.name} execution failed: {e}", exc_info=True)
                return ToolMessage(
                    tool_call_id=call.id,
                    name=call.name,
                    content=f'{{"error": "Execution failed: {str(e)}"}}'
                )

        results = await asyncio.gather(*(safe_execute(call) for call in calls))
        return list(results)