"""
LockStock Claude Agent SDK Hooks
---------------------------------
Pre-tool-execution hooks for Claude Agent SDK.

Uses the thin client pattern - all verification happens server-side via /v1/stamp.

Usage:
    from lockstock_claude import LockStockHook

    hook = LockStockHook(
        agent_id="agent_abc123",
        api_key="lsk_admin_..."
    )

    # In your Claude Agent SDK configuration
    agent = Agent(
        hooks={
            "pre_tool_use": hook.pre_tool_execution
        }
    )
"""

import asyncio
from typing import Dict, Any, Optional, Callable, Awaitable
from dataclasses import dataclass

from lockstock_core import LockStockClient, VerifyResult
from lockstock_core.types import map_tool_to_capability


@dataclass
class ToolExecutionContext:
    """Context for a tool execution."""
    tool_name: str
    tool_input: Dict[str, Any]
    agent_id: str
    sequence: int


class LockStockHook:
    """
    Pre-tool-execution hook for Claude Agent SDK.

    Intercepts tool calls and stamps authorization with LockStock
    before allowing execution.
    """

    def __init__(
        self,
        agent_id: str,
        api_key: str,
        endpoint: str = "https://lockstock-api-i9kp.onrender.com",
        on_denied: Optional[Callable[[ToolExecutionContext, str], Awaitable[None]]] = None,
        on_approved: Optional[Callable[[ToolExecutionContext], Awaitable[None]]] = None,
        strict_mode: bool = True
    ):
        """
        Initialize LockStock hook.

        Args:
            agent_id: The agent's unique identifier
            api_key: API key for authentication (from dashboard)
            endpoint: LockStock API endpoint
            on_denied: Callback when a tool is denied
            on_approved: Callback when a tool is approved
            strict_mode: If True, raise on denial. If False, just log.
        """
        self.client = LockStockClient(
            agent_id=agent_id,
            api_key=api_key,
            endpoint=endpoint
        )
        self.agent_id = agent_id
        self.on_denied = on_denied
        self.on_approved = on_approved
        self.strict_mode = strict_mode
        self._sequence = 0

    async def pre_tool_execution(
        self,
        tool_name: str,
        tool_input: Dict[str, Any]
    ) -> bool:
        """
        Intercept tool calls and stamp authorization.

        Args:
            tool_name: Name of the tool being called
            tool_input: The tool's input parameters

        Returns:
            True if authorized

        Raises:
            PermissionError: If not authorized and strict_mode is True
        """
        self._sequence += 1

        # Map tool to capability
        capability = map_tool_to_capability(tool_name)

        # Create execution context
        context = ToolExecutionContext(
            tool_name=tool_name,
            tool_input=tool_input,
            agent_id=self.agent_id,
            sequence=self._sequence
        )

        # Stamp with LockStock
        result = await self.client.stamp_tool(tool_name=tool_name)

        if result.authorized:
            # Tool is approved
            if self.on_approved:
                await self.on_approved(context)

            return True
        else:
            # Tool is denied
            reason = result.reason or f"Not authorized for capability: {capability}"

            if self.on_denied:
                await self.on_denied(context, reason)

            if self.strict_mode:
                raise PermissionError(
                    f"[LockStock] DENIED: Agent {self.agent_id} "
                    f"cannot use tool '{tool_name}' (requires {capability}). "
                    f"Reason: {reason}"
                )

            return False

    async def close(self):
        """Close the underlying client."""
        await self.client.close()

    def __del__(self):
        """Cleanup on deletion."""
        try:
            loop = asyncio.get_event_loop()
            if loop.is_running():
                loop.create_task(self.close())
            else:
                loop.run_until_complete(self.close())
        except Exception:
            pass


def create_pre_tool_hook(
    agent_id: str,
    api_key: str,
    endpoint: str = "https://lockstock-api-i9kp.onrender.com",
    strict_mode: bool = True
) -> Callable[[str, Dict[str, Any]], Awaitable[bool]]:
    """
    Factory function to create a pre-tool-execution hook.

    Args:
        agent_id: The agent's unique identifier
        api_key: API key for authentication (from dashboard)
        endpoint: LockStock API endpoint
        strict_mode: If True, raise on denial

    Returns:
        Async function suitable for use as a pre-tool hook
    """
    hook = LockStockHook(
        agent_id=agent_id,
        api_key=api_key,
        endpoint=endpoint,
        strict_mode=strict_mode
    )

    return hook.pre_tool_execution
