from pygeai import logger
from pygeai.core.utils.validators import validate_status_code
from pygeai.core.utils.parsers import parse_json_response
from pygeai.core.common.exceptions import InvalidAPIResponseException
from pygeai.lab.plugins.tools.endpoints import (
    LIST_TOOL_PLUGINS_V4,
    GET_TOOL_PLUGIN_V4,
    GET_TOOL_PLUGIN_CONFIG_V4,
    SET_TOOL_PLUGIN_CONFIG_V4
)
from pygeai.lab.clients import AILabClient


class ToolPluginClient(AILabClient):
    """
    Client for Tool-Plugin API operations.
    
    This client provides methods to interact with tool-plugin endpoints for managing
    tool-plugin configurations, including parameter inheritance and overrides.
    """

    def list_plugins(
            self,
            count: str = "100",
            access_scope: str = "private",
            allow_drafts: bool = True
    ) -> dict:
        """
        Retrieves a list of tool-plugins associated with the specified project.

        :param count: str - Number of tool-plugins to retrieve. Defaults to "100".
        :param access_scope: str - Access scope of the plugins, either "public" or "private". Defaults to "private".
        :param allow_drafts: bool - Whether to include draft plugins. Defaults to True.
        :return: dict - JSON response containing the list of tool-plugins if successful, otherwise the raw response text.
        :raises APIError: If the API returns an error status code.
        
        Note: This endpoint may not be available yet. If it returns 404, the feature is not implemented.
        """
        endpoint = LIST_TOOL_PLUGINS_V4.format(projectId=self.project_id)
        
        logger.debug(f"Listing tool-plugins for project {self.project_id}")

        try:
            response = self.api_service.get(
                endpoint=endpoint,
                params={
                    "count": count,
                    "accessScope": access_scope,
                    "allowDrafts": allow_drafts
                }
            )
            validate_status_code(response)
            return parse_json_response(response, f"list tool-plugins for project {self.project_id}")
        except Exception as e:
            if "404" in str(e):
                raise InvalidAPIResponseException(
                    "Tool-plugin list endpoint is not available yet. "
                    "This feature may not be implemented on the server."
                ) from e
            raise

    def get_plugin(
            self,
            plugin_id_or_name: str,
            revision: str = "0",
            version: int = 0,
            allow_drafts: bool = True
    ) -> dict:
        """
        Retrieves details of a specific tool-plugin from the specified project.

        :param plugin_id_or_name: str - Unique identifier or name of the tool-plugin to retrieve.
        :param revision: str - Revision of the plugin to retrieve. Defaults to "0" (latest revision).
        :param version: int - Version of the plugin to retrieve. Defaults to 0 (latest version).
        :param allow_drafts: bool - Whether to include draft plugin in the retrieval. Defaults to True.
        :return: dict - JSON response containing the plugin details if successful, otherwise the raw response text.
        :raises APIError: If the API returns an error status code.
        
        Note: This endpoint may not be available yet. If it returns 404, the feature is not implemented.
        """
        endpoint = GET_TOOL_PLUGIN_V4.format(
            projectId=self.project_id,
            pluginIdOrName=plugin_id_or_name
        )
        
        logger.debug(f"Retrieving tool-plugin {plugin_id_or_name} for project {self.project_id}")

        try:
            response = self.api_service.get(
                endpoint=endpoint,
                params={
                    "revision": revision,
                    "version": version,
                    "allowDrafts": allow_drafts
                }
            )
            validate_status_code(response)
            return parse_json_response(response, f"get tool-plugin {plugin_id_or_name} for project {self.project_id}")
        except Exception as e:
            if "404" in str(e):
                raise InvalidAPIResponseException(
                    f"Tool-plugin get endpoint is not available yet. "
                    f"This feature may not be implemented on the server."
                ) from e
            raise

    def get_config(
            self,
            plugin_id_or_name: str,
            revision: str = "0",
            version: int = 0,
            allow_drafts: bool = True
    ) -> dict:
        """
        Retrieves the configuration (parameters) for a specific tool-plugin in the current project context.

        This method returns the parameters defined at the tool-plugin level, which can be inherited
        by tools belonging to the plugin.

        :param plugin_id_or_name: str - Unique identifier or name of the tool-plugin.
        :param revision: str - Revision of the configuration to retrieve. Defaults to "0" (latest revision).
        :param version: int - Version of the configuration to retrieve. Defaults to 0 (latest version).
        :param allow_drafts: bool - Whether to include draft configuration. Defaults to True.
        :return: dict - JSON response containing the plugin configuration (parameters) if successful.
        :raises InvalidAPIResponseException: If the endpoint is not available (404) or other errors occur.
        
        Note: This endpoint may not be available yet. If it returns 404, the feature is not implemented.
        
        Example response:
        {
            "parameters": [
                {
                    "key": "securityScheme.flows.authorizationCode.clientId",
                    "dataType": "String",
                    "fromSecret": true,
                    "isRequired": true,
                    "type": "config",
                    "value": "myGoogleClientIdSecret"
                }
            ]
        }
        """
        endpoint = GET_TOOL_PLUGIN_CONFIG_V4.format(
            projectId=self.project_id,
            pluginIdOrName=plugin_id_or_name
        )
        
        logger.debug(f"Retrieving config for tool-plugin {plugin_id_or_name} in project {self.project_id}")

        try:
            response = self.api_service.get(
                endpoint=endpoint,
                params={
                    "revision": revision,
                    "version": version,
                    "allowDrafts": allow_drafts
                }
            )
            validate_status_code(response)
            return parse_json_response(response, f"get config for tool-plugin {plugin_id_or_name} in project {self.project_id}")
        except Exception as e:
            if "404" in str(e):
                raise InvalidAPIResponseException(
                    f"Tool-plugin config endpoint is not available yet. "
                    f"This feature may not be implemented on the server. "
                    f"Endpoint: {endpoint}"
                ) from e
            raise

    def set_config(
            self,
            plugin_id_or_name: str,
            parameters: list
    ) -> dict:
        """
        Sets or updates the configuration (parameters) for a specific tool-plugin in the current project context.

        This method allows setting parameter values at the tool-plugin level, which can then be inherited
        by tools belonging to the plugin.

        :param plugin_id_or_name: str - Unique identifier or name of the tool-plugin.
        :param parameters: list - List of parameter dictionaries defining the plugin's parameters.
                                  Each dictionary must contain 'key', 'type', 'value', and optionally 'description'.
        :return: dict - JSON response containing the result of the set operation if successful.
        :raises ValueError: If parameters list is None or empty.
        :raises InvalidAPIResponseException: If the endpoint is not available (404) or other errors occur.
        
        Note: This endpoint may not be available yet. If it returns 404, the feature is not implemented.
        
        Example parameters:
        [
            {
                "key": "securityScheme.flows.authorizationCode.clientId",
                "type": "config",
                "value": "myGoogleClientIdSecret",
                "description": "The name of the secret that contains the value of clientId"
            }
        ]
        """
        if not parameters:
            raise ValueError("Parameters list must be provided and non-empty.")

        endpoint = SET_TOOL_PLUGIN_CONFIG_V4.format(
            projectId=self.project_id,
            pluginIdOrName=plugin_id_or_name
        )

        data = {
            "parameterDefinition": {
                "parameters": parameters
            }
        }

        logger.debug(f"Setting config for tool-plugin {plugin_id_or_name} in project {self.project_id} with data: {data}")

        try:
            response = self.api_service.post(
                endpoint=endpoint,
                data=data
            )
            
            # Accept both 200 and 204 status codes
            if response.status_code not in [200, 204]:
                logger.error(
                    f"Unable to set config for tool-plugin {plugin_id_or_name} in project {self.project_id}: "
                    f"status {response.status_code}. Response: {response.text}"
                )
                raise InvalidAPIResponseException(
                    f"Unable to set config for tool-plugin {plugin_id_or_name} in project {self.project_id}: "
                    f"{response.text}"
                )
            
            # Return empty dict for 204, parse JSON for 200
            if response.status_code == 204:
                return {}
            else:
                return parse_json_response(response, f"set config for tool-plugin {plugin_id_or_name} in project {self.project_id}")
                
        except Exception as e:
            if "404" in str(e):
                raise InvalidAPIResponseException(
                    f"Tool-plugin config endpoint is not available yet. "
                    f"This feature may not be implemented on the server. "
                    f"Endpoint: {endpoint}"
                ) from e
            raise
