from typing import Optional

from core.extension.api_based_extension_requestor import APIBasedExtensionRequestor
from core.external_data_tool.base import ExternalDataTool
from core.helper import encrypter
from extensions.ext_database import db
from models.api_based_extension import APIBasedExtension, APIBasedExtensionPoint


class ApiExternalDataTool(ExternalDataTool):
    """
    The api external data tool.
    """

    name: str = "api"
    """the unique name of external data tool"""

    @classmethod
    def validate_config(cls, tenant_id: str, config: dict) -> None:
        """
        Validate the incoming form config data.

        :param tenant_id: the id of workspace
        :param config: the form config data
        :return:
        """
        # own validation logic
        api_based_extension_id = config.get("api_based_extension_id")
        if not api_based_extension_id:
            raise ValueError("api_based_extension_id is required")

        # get api_based_extension
        api_based_extension = db.session.query(APIBasedExtension).filter(
            APIBasedExtension.tenant_id == tenant_id,
            APIBasedExtension.id == api_based_extension_id
        ).first()

        if not api_based_extension:
            raise ValueError("api_based_extension_id is invalid")

    def query(self, inputs: dict, query: Optional[str] = None) -> str:
        """
        Query the external data tool.

        :param inputs: user inputs
        :param query: the query of chat app
        :return: the tool query result
        """
        # get params from config
        api_based_extension_id = self.config.get("api_based_extension_id")

        # get api_based_extension
        api_based_extension = db.session.query(APIBasedExtension).filter(
            APIBasedExtension.tenant_id == self.tenant_id,
            APIBasedExtension.id == api_based_extension_id
        ).first()

        if not api_based_extension:
            raise ValueError("[External data tool] API query failed, variable: {}, "
                             "error: api_based_extension_id is invalid"
                             .format(self.variable))

        # decrypt api_key
        api_key = encrypter.decrypt_token(
            tenant_id=self.tenant_id,
            token=api_based_extension.api_key
        )

        try:
            # request api
            requestor = APIBasedExtensionRequestor(
                api_endpoint=api_based_extension.api_endpoint,
                api_key=api_key
            )
        except Exception as e:
            raise ValueError("[External data tool] API query failed, variable: {}, error: {}".format(
                self.variable,
                e
            ))

        response_json = requestor.request(point=APIBasedExtensionPoint.APP_EXTERNAL_DATA_TOOL_QUERY, params={
            'app_id': self.app_id,
            'tool_variable': self.variable,
            'inputs': inputs,
            'query': query
        })

        if 'result' not in response_json:
            raise ValueError("[External data tool] API query failed, variable: {}, error: result not found in response"
                             .format(self.variable))

        if not isinstance(response_json['result'], str):
            raise ValueError("[External data tool] API query failed, variable: {}, error: result is not string"
                             .format(self.variable))

        return response_json['result']
