"""Command helpers for JsonRpcClient.

Author: Vasiliy Zdanovskiy
email: vasilyvz@gmail.com
"""

from __future__ import annotations

from typing import Any, Dict, Optional, TYPE_CHECKING

from mcp_proxy_adapter.client.jsonrpc_client.transport import JsonRpcTransport

if TYPE_CHECKING:
    from mcp_proxy_adapter.client.jsonrpc_client.schema_generator import MethodInfo


class CommandApiMixin(JsonRpcTransport):
    """Mixin providing standard JSON-RPC command helpers."""

    async def echo(
        self, message: str = "Hello, World!", timestamp: Optional[str] = None
    ) -> Dict[str, Any]:
        params: Dict[str, Any] = {"message": message}
        if timestamp:
            params["timestamp"] = timestamp
        response = await self.jsonrpc_call("echo", params)
        return self._extract_result(response)

    async def help(
        self, command_name: Optional[str] = None
    ) -> Dict[str, Any]:
        params: Dict[str, Any] = {}
        if command_name:
            params["command"] = command_name
        response = await self.jsonrpc_call("help", params)
        return self._extract_result(response)

    async def get_config(self) -> Dict[str, Any]:
        response = await self.jsonrpc_call("config", {})
        return self._extract_result(response)

    async def long_task(self, seconds: int) -> Dict[str, Any]:
        response = await self.jsonrpc_call("long_task", {"seconds": seconds})
        return self._extract_result(response)

    async def job_status(self, job_id: str) -> Dict[str, Any]:
        response = await self.jsonrpc_call("job_status", {"job_id": job_id})
        return self._extract_result(response)

    async def execute_command(
        self,
        command: str,
        params: Optional[Dict[str, Any]] = None,
        use_cmd_endpoint: bool = False,
    ) -> Dict[str, Any]:
        """
        Execute command using either /cmd endpoint or JSON-RPC.
        
        The /cmd endpoint supports the CommandRequest schema with oneOf discriminator
        and detailed parameter validation. Use use_cmd_endpoint=True to use this endpoint.
        
        Args:
            command: Command name to execute
            params: Optional command parameters
            use_cmd_endpoint: If True, use /cmd endpoint; otherwise use JSON-RPC
            
        Returns:
            Command execution result
        """
        if use_cmd_endpoint:
            return await self.cmd_call(command, params)
        else:
            response = await self.jsonrpc_call(command, params or {})
            return self._extract_result(response)
    
    async def execute(
        self,
        method_name: str,
        params: Optional[Dict[str, Any]] = None,
    ) -> Dict[str, Any]:
        """
        Execute method with schema-based validation and default values.
        
        This method uses the SchemaRequestGenerator to:
        - Validate required parameters
        - Set default values for missing optional parameters
        - Validate parameter types
        - Execute the command and return deserialized Python object
        
        Args:
            method_name: Name of the method to execute
            params: Method parameters (optional)
            
        Returns:
            Deserialized command execution result (Python dict)
            
        Raises:
            MethodNotFoundError: If method is not found in schema
            RequiredParameterMissingError: If required parameter is missing
            InvalidParameterTypeError: If parameter type is invalid
            InvalidParameterValueError: If parameter value is invalid
            RuntimeError: If command execution fails
        """
        from mcp_proxy_adapter.client.jsonrpc_client.schema_generator import SchemaRequestGenerator
        from mcp_proxy_adapter.client.jsonrpc_client.exceptions import (
            MethodNotFoundError,
            RequiredParameterMissingError,
            InvalidParameterTypeError,
            InvalidParameterValueError,
        )
        
        # Get schema generator
        generator = await self.get_schema_generator_async()
        
        # Validate and prepare parameters
        try:
            prepared_params = generator.validate_and_prepare_params(method_name, params)
        except (MethodNotFoundError, RequiredParameterMissingError, 
                InvalidParameterTypeError, InvalidParameterValueError) as e:
            raise  # Re-raise schema validation errors
        
        # Execute command
        result = await self.cmd_call(method_name, prepared_params)
        
        # Result is already a Python dict (deserialized JSON)
        return result
    
    async def get_methods(self) -> Dict[str, "MethodInfo"]:
        """
        Get all available methods with their descriptions.
        
        Returns:
            Dictionary mapping method names to MethodInfo objects
        """
        generator = await self.get_schema_generator_async()
        return generator.get_methods()
    
    async def get_method_description(self, method_name: str) -> str:
        """
        Get detailed description of a method.
        
        Args:
            method_name: Name of the method
            
        Returns:
            Detailed description string including:
            - Method name and description
            - Return type and description
            - Parameter details (type, description, default, required)
        """
        generator = await self.get_schema_generator_async()
        return generator.get_method_description(method_name)
    
    async def schema_example(self) -> str:
        """
        Get schema example with detailed descriptions.
        
        Returns:
            JSON string containing:
            - Full OpenAPI schema
            - Standard description (OpenAPI 3.0.2)
            - Detailed field descriptions
            - All methods with parameter details
        """
        generator = await self.get_schema_generator_async()
        return generator.schema_example()
