# coding: utf-8

"""
Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
"""
from __future__ import annotations

from json import dumps
from typing import Annotated, Any, Dict, List, Optional, Self, Tuple, Union
from urllib.parse import quote

from pydantic import Field, StrictInt, StrictStr

from algoliasearch.abtesting.config import AbtestingConfig
from algoliasearch.abtesting.models.ab_test import ABTest
from algoliasearch.abtesting.models.ab_test_response import ABTestResponse
from algoliasearch.abtesting.models.add_ab_tests_request import AddABTestsRequest
from algoliasearch.abtesting.models.list_ab_tests_response import ListABTestsResponse
from algoliasearch.http.api_response import ApiResponse
from algoliasearch.http.request_options import RequestOptions
from algoliasearch.http.serializer import bodySerializer
from algoliasearch.http.transporter import Transporter
from algoliasearch.http.verb import Verb


class AbtestingClient:
    """The Algolia 'AbtestingClient' class.

    Args:
    app_id (str): The Algolia application ID to retrieve information from.
    api_key (str): The Algolia api key bound to the given `app_id`.
    region ("de" | "us"): The region of your Algolia application.

    Returns:
    The initialized API client.

    Example:
    _client = AbtestingClient("YOUR_ALGOLIA_APP_ID", "YOUR_ALGOLIA_API_KEY", region="'de' or 'us'")
    _client_with_named_args = AbtestingClient(app_id="YOUR_ALGOLIA_APP_ID", api_key="YOUR_ALGOLIA_API_KEY", region="'de' or 'us'")

    See `AbtestingClient.create_with_config` for advanced configuration.
    """

    _transporter: Transporter
    _config: AbtestingConfig
    _request_options: RequestOptions

    def __init__(
        self,
        app_id: Optional[str] = None,
        api_key: Optional[str] = None,
        region: Optional[str] = None,
        transporter: Optional[Transporter] = None,
        config: Optional[AbtestingConfig] = None,
    ) -> None:
        if transporter is not None and config is None:
            config = transporter._config

        if config is None:
            config = AbtestingConfig(app_id, api_key, region)
        self._config = config
        self._request_options = RequestOptions(config)

        if transporter is None:
            transporter = Transporter(config)
        self._transporter = transporter

    def create_with_config(
        config: AbtestingConfig, transporter: Optional[Transporter] = None
    ) -> Self:
        """Allows creating a client with a customized `AbtestingConfig` and `Transporter`. If `transporter` is not provided, the default one will be initialized from the given `config`.

        Args:
        config (AbtestingConfig): The config of the API client.
        transporter (Transporter): The HTTP transporter, see `http/transporter.py` for implementation details.

        Returns:
        The initialized API client.

        Example:
        _client_with_custom_config = AbtestingClient.create_with_config(config=AbtestingConfig(...))
        _client_with_custom_config_and_transporter = AbtestingClient.create_with_config(config=AbtestingConfig(...), transporter=Transporter(...))
        """
        if transporter is None:
            transporter = Transporter(config)

        return AbtestingClient(
            app_id=config.app_id,
            api_key=config.api_key,
            region=config.region,
            transporter=transporter,
            config=config,
        )

    async def __aenter__(self) -> None:
        return self

    async def __aexit__(self, exc_type, exc_value, traceback) -> None:
        """Closes the underlying `transporter` of the API client."""
        await self.close()

    async def close(self) -> None:
        """Closes the underlying `transporter` of the API client."""
        return await self._transporter.close()

    async def add_ab_tests_with_http_info(
        self,
        add_ab_tests_request: AddABTestsRequest,
        request_options: Optional[Union[dict, RequestOptions]] = None,
    ) -> ApiResponse[str]:
        """
        Creates an A/B test.

        Required API Key ACLs:
          - editSettings

        :param add_ab_tests_request: (required)
        :type add_ab_tests_request: AddABTestsRequest
        :param request_options: The request options to send along with the query, they will be merged with the transporter base parameters (headers, query params, timeouts, etc.). (optional)
        :return: Returns the raw algoliasearch 'APIResponse' object.
        """

        if add_ab_tests_request is None:
            raise ValueError(
                "Parameter `add_ab_tests_request` is required when calling `add_ab_tests`."
            )

        _data = {}
        if add_ab_tests_request is not None:
            _data = add_ab_tests_request

        return await self._transporter.request(
            verb=Verb.POST,
            path="/2/abtests",
            request_options=self._request_options.merge(
                data=dumps(bodySerializer(_data)),
                user_request_options=request_options,
            ),
            use_read_transporter=False,
        )

    async def add_ab_tests(
        self,
        add_ab_tests_request: AddABTestsRequest,
        request_options: Optional[Union[dict, RequestOptions]] = None,
    ) -> ABTestResponse:
        """
        Creates an A/B test.

        Required API Key ACLs:
          - editSettings

        :param add_ab_tests_request: (required)
        :type add_ab_tests_request: AddABTestsRequest
        :param request_options: The request options to send along with the query, they will be merged with the transporter base parameters (headers, query params, timeouts, etc.). (optional)
        :return: Returns the deserialized response in a 'ABTestResponse' result object.
        """
        return (
            await self.add_ab_tests_with_http_info(
                add_ab_tests_request, request_options
            )
        ).deserialize(ABTestResponse)

    async def custom_delete_with_http_info(
        self,
        path: Annotated[
            StrictStr,
            Field(
                description='Path of the endpoint, anything after "/1" must be specified.'
            ),
        ],
        parameters: Annotated[
            Optional[Dict[str, Any]],
            Field(description="Query parameters to apply to the current query."),
        ] = None,
        request_options: Optional[Union[dict, RequestOptions]] = None,
    ) -> ApiResponse[str]:
        """
        This method allow you to send requests to the Algolia REST API.


        :param path: Path of the endpoint, anything after \"/1\" must be specified. (required)
        :type path: str
        :param parameters: Query parameters to apply to the current query.
        :type parameters: Dict[str, object]
        :param request_options: The request options to send along with the query, they will be merged with the transporter base parameters (headers, query params, timeouts, etc.). (optional)
        :return: Returns the raw algoliasearch 'APIResponse' object.
        """

        if path is None:
            raise ValueError(
                "Parameter `path` is required when calling `custom_delete`."
            )

        _query_parameters: List[Tuple[str, str]] = []

        if parameters is not None:
            for _qpkey, _qpvalue in parameters.items():
                _query_parameters.append((_qpkey, _qpvalue))

        return await self._transporter.request(
            verb=Verb.DELETE,
            path="/{path}".replace("{path}", path),
            request_options=self._request_options.merge(
                query_parameters=_query_parameters,
                user_request_options=request_options,
            ),
            use_read_transporter=False,
        )

    async def custom_delete(
        self,
        path: Annotated[
            StrictStr,
            Field(
                description='Path of the endpoint, anything after "/1" must be specified.'
            ),
        ],
        parameters: Annotated[
            Optional[Dict[str, Any]],
            Field(description="Query parameters to apply to the current query."),
        ] = None,
        request_options: Optional[Union[dict, RequestOptions]] = None,
    ) -> object:
        """
        This method allow you to send requests to the Algolia REST API.


        :param path: Path of the endpoint, anything after \"/1\" must be specified. (required)
        :type path: str
        :param parameters: Query parameters to apply to the current query.
        :type parameters: Dict[str, object]
        :param request_options: The request options to send along with the query, they will be merged with the transporter base parameters (headers, query params, timeouts, etc.). (optional)
        :return: Returns the deserialized response in a 'object' result object.
        """
        return (
            await self.custom_delete_with_http_info(path, parameters, request_options)
        ).deserialize(object)

    async def custom_get_with_http_info(
        self,
        path: Annotated[
            StrictStr,
            Field(
                description='Path of the endpoint, anything after "/1" must be specified.'
            ),
        ],
        parameters: Annotated[
            Optional[Dict[str, Any]],
            Field(description="Query parameters to apply to the current query."),
        ] = None,
        request_options: Optional[Union[dict, RequestOptions]] = None,
    ) -> ApiResponse[str]:
        """
        This method allow you to send requests to the Algolia REST API.


        :param path: Path of the endpoint, anything after \"/1\" must be specified. (required)
        :type path: str
        :param parameters: Query parameters to apply to the current query.
        :type parameters: Dict[str, object]
        :param request_options: The request options to send along with the query, they will be merged with the transporter base parameters (headers, query params, timeouts, etc.). (optional)
        :return: Returns the raw algoliasearch 'APIResponse' object.
        """

        if path is None:
            raise ValueError("Parameter `path` is required when calling `custom_get`.")

        _query_parameters: List[Tuple[str, str]] = []

        if parameters is not None:
            for _qpkey, _qpvalue in parameters.items():
                _query_parameters.append((_qpkey, _qpvalue))

        return await self._transporter.request(
            verb=Verb.GET,
            path="/{path}".replace("{path}", path),
            request_options=self._request_options.merge(
                query_parameters=_query_parameters,
                user_request_options=request_options,
            ),
            use_read_transporter=False,
        )

    async def custom_get(
        self,
        path: Annotated[
            StrictStr,
            Field(
                description='Path of the endpoint, anything after "/1" must be specified.'
            ),
        ],
        parameters: Annotated[
            Optional[Dict[str, Any]],
            Field(description="Query parameters to apply to the current query."),
        ] = None,
        request_options: Optional[Union[dict, RequestOptions]] = None,
    ) -> object:
        """
        This method allow you to send requests to the Algolia REST API.


        :param path: Path of the endpoint, anything after \"/1\" must be specified. (required)
        :type path: str
        :param parameters: Query parameters to apply to the current query.
        :type parameters: Dict[str, object]
        :param request_options: The request options to send along with the query, they will be merged with the transporter base parameters (headers, query params, timeouts, etc.). (optional)
        :return: Returns the deserialized response in a 'object' result object.
        """
        return (
            await self.custom_get_with_http_info(path, parameters, request_options)
        ).deserialize(object)

    async def custom_post_with_http_info(
        self,
        path: Annotated[
            StrictStr,
            Field(
                description='Path of the endpoint, anything after "/1" must be specified.'
            ),
        ],
        parameters: Annotated[
            Optional[Dict[str, Any]],
            Field(description="Query parameters to apply to the current query."),
        ] = None,
        body: Annotated[
            Optional[Dict[str, Any]],
            Field(description="Parameters to send with the custom request."),
        ] = None,
        request_options: Optional[Union[dict, RequestOptions]] = None,
    ) -> ApiResponse[str]:
        """
        This method allow you to send requests to the Algolia REST API.


        :param path: Path of the endpoint, anything after \"/1\" must be specified. (required)
        :type path: str
        :param parameters: Query parameters to apply to the current query.
        :type parameters: Dict[str, object]
        :param body: Parameters to send with the custom request.
        :type body: object
        :param request_options: The request options to send along with the query, they will be merged with the transporter base parameters (headers, query params, timeouts, etc.). (optional)
        :return: Returns the raw algoliasearch 'APIResponse' object.
        """

        if path is None:
            raise ValueError("Parameter `path` is required when calling `custom_post`.")

        _query_parameters: List[Tuple[str, str]] = []

        if parameters is not None:
            for _qpkey, _qpvalue in parameters.items():
                _query_parameters.append((_qpkey, _qpvalue))

        _data = {}
        if body is not None:
            _data = body

        return await self._transporter.request(
            verb=Verb.POST,
            path="/{path}".replace("{path}", path),
            request_options=self._request_options.merge(
                query_parameters=_query_parameters,
                data=dumps(bodySerializer(_data)),
                user_request_options=request_options,
            ),
            use_read_transporter=False,
        )

    async def custom_post(
        self,
        path: Annotated[
            StrictStr,
            Field(
                description='Path of the endpoint, anything after "/1" must be specified.'
            ),
        ],
        parameters: Annotated[
            Optional[Dict[str, Any]],
            Field(description="Query parameters to apply to the current query."),
        ] = None,
        body: Annotated[
            Optional[Dict[str, Any]],
            Field(description="Parameters to send with the custom request."),
        ] = None,
        request_options: Optional[Union[dict, RequestOptions]] = None,
    ) -> object:
        """
        This method allow you to send requests to the Algolia REST API.


        :param path: Path of the endpoint, anything after \"/1\" must be specified. (required)
        :type path: str
        :param parameters: Query parameters to apply to the current query.
        :type parameters: Dict[str, object]
        :param body: Parameters to send with the custom request.
        :type body: object
        :param request_options: The request options to send along with the query, they will be merged with the transporter base parameters (headers, query params, timeouts, etc.). (optional)
        :return: Returns the deserialized response in a 'object' result object.
        """
        return (
            await self.custom_post_with_http_info(
                path, parameters, body, request_options
            )
        ).deserialize(object)

    async def custom_put_with_http_info(
        self,
        path: Annotated[
            StrictStr,
            Field(
                description='Path of the endpoint, anything after "/1" must be specified.'
            ),
        ],
        parameters: Annotated[
            Optional[Dict[str, Any]],
            Field(description="Query parameters to apply to the current query."),
        ] = None,
        body: Annotated[
            Optional[Dict[str, Any]],
            Field(description="Parameters to send with the custom request."),
        ] = None,
        request_options: Optional[Union[dict, RequestOptions]] = None,
    ) -> ApiResponse[str]:
        """
        This method allow you to send requests to the Algolia REST API.


        :param path: Path of the endpoint, anything after \"/1\" must be specified. (required)
        :type path: str
        :param parameters: Query parameters to apply to the current query.
        :type parameters: Dict[str, object]
        :param body: Parameters to send with the custom request.
        :type body: object
        :param request_options: The request options to send along with the query, they will be merged with the transporter base parameters (headers, query params, timeouts, etc.). (optional)
        :return: Returns the raw algoliasearch 'APIResponse' object.
        """

        if path is None:
            raise ValueError("Parameter `path` is required when calling `custom_put`.")

        _query_parameters: List[Tuple[str, str]] = []

        if parameters is not None:
            for _qpkey, _qpvalue in parameters.items():
                _query_parameters.append((_qpkey, _qpvalue))

        _data = {}
        if body is not None:
            _data = body

        return await self._transporter.request(
            verb=Verb.PUT,
            path="/{path}".replace("{path}", path),
            request_options=self._request_options.merge(
                query_parameters=_query_parameters,
                data=dumps(bodySerializer(_data)),
                user_request_options=request_options,
            ),
            use_read_transporter=False,
        )

    async def custom_put(
        self,
        path: Annotated[
            StrictStr,
            Field(
                description='Path of the endpoint, anything after "/1" must be specified.'
            ),
        ],
        parameters: Annotated[
            Optional[Dict[str, Any]],
            Field(description="Query parameters to apply to the current query."),
        ] = None,
        body: Annotated[
            Optional[Dict[str, Any]],
            Field(description="Parameters to send with the custom request."),
        ] = None,
        request_options: Optional[Union[dict, RequestOptions]] = None,
    ) -> object:
        """
        This method allow you to send requests to the Algolia REST API.


        :param path: Path of the endpoint, anything after \"/1\" must be specified. (required)
        :type path: str
        :param parameters: Query parameters to apply to the current query.
        :type parameters: Dict[str, object]
        :param body: Parameters to send with the custom request.
        :type body: object
        :param request_options: The request options to send along with the query, they will be merged with the transporter base parameters (headers, query params, timeouts, etc.). (optional)
        :return: Returns the deserialized response in a 'object' result object.
        """
        return (
            await self.custom_put_with_http_info(
                path, parameters, body, request_options
            )
        ).deserialize(object)

    async def delete_ab_test_with_http_info(
        self,
        id: Annotated[StrictInt, Field(description="Unique A/B test ID.")],
        request_options: Optional[Union[dict, RequestOptions]] = None,
    ) -> ApiResponse[str]:
        """
        Delete an A/B test. To determine the `id` for an A/B test, use the [`listABTests` operation](#tag/abtest/operation/listABTests).

        Required API Key ACLs:
          - editSettings

        :param id: Unique A/B test ID. (required)
        :type id: int
        :param request_options: The request options to send along with the query, they will be merged with the transporter base parameters (headers, query params, timeouts, etc.). (optional)
        :return: Returns the raw algoliasearch 'APIResponse' object.
        """

        if id is None:
            raise ValueError(
                "Parameter `id` is required when calling `delete_ab_test`."
            )

        return await self._transporter.request(
            verb=Verb.DELETE,
            path="/2/abtests/{id}".replace("{id}", quote(str(id), safe="")),
            request_options=self._request_options.merge(
                user_request_options=request_options,
            ),
            use_read_transporter=False,
        )

    async def delete_ab_test(
        self,
        id: Annotated[StrictInt, Field(description="Unique A/B test ID.")],
        request_options: Optional[Union[dict, RequestOptions]] = None,
    ) -> ABTestResponse:
        """
        Delete an A/B test. To determine the `id` for an A/B test, use the [`listABTests` operation](#tag/abtest/operation/listABTests).

        Required API Key ACLs:
          - editSettings

        :param id: Unique A/B test ID. (required)
        :type id: int
        :param request_options: The request options to send along with the query, they will be merged with the transporter base parameters (headers, query params, timeouts, etc.). (optional)
        :return: Returns the deserialized response in a 'ABTestResponse' result object.
        """
        return (
            await self.delete_ab_test_with_http_info(id, request_options)
        ).deserialize(ABTestResponse)

    async def get_ab_test_with_http_info(
        self,
        id: Annotated[StrictInt, Field(description="Unique A/B test ID.")],
        request_options: Optional[Union[dict, RequestOptions]] = None,
    ) -> ApiResponse[str]:
        """
        Get specific details for an A/B test. To determine the `id` for an A/B test, use the [`listABTests` operation](#tag/abtest/operation/listABTests).

        Required API Key ACLs:
          - analytics

        :param id: Unique A/B test ID. (required)
        :type id: int
        :param request_options: The request options to send along with the query, they will be merged with the transporter base parameters (headers, query params, timeouts, etc.). (optional)
        :return: Returns the raw algoliasearch 'APIResponse' object.
        """

        if id is None:
            raise ValueError("Parameter `id` is required when calling `get_ab_test`.")

        return await self._transporter.request(
            verb=Verb.GET,
            path="/2/abtests/{id}".replace("{id}", quote(str(id), safe="")),
            request_options=self._request_options.merge(
                user_request_options=request_options,
            ),
            use_read_transporter=False,
        )

    async def get_ab_test(
        self,
        id: Annotated[StrictInt, Field(description="Unique A/B test ID.")],
        request_options: Optional[Union[dict, RequestOptions]] = None,
    ) -> ABTest:
        """
        Get specific details for an A/B test. To determine the `id` for an A/B test, use the [`listABTests` operation](#tag/abtest/operation/listABTests).

        Required API Key ACLs:
          - analytics

        :param id: Unique A/B test ID. (required)
        :type id: int
        :param request_options: The request options to send along with the query, they will be merged with the transporter base parameters (headers, query params, timeouts, etc.). (optional)
        :return: Returns the deserialized response in a 'ABTest' result object.
        """
        return (await self.get_ab_test_with_http_info(id, request_options)).deserialize(
            ABTest
        )

    async def list_ab_tests_with_http_info(
        self,
        offset: Annotated[
            Optional[Annotated[int, Field(strict=True, ge=0)]],
            Field(description="Position of the first item to return."),
        ] = None,
        limit: Annotated[
            Optional[StrictInt], Field(description="Number of items to return.")
        ] = None,
        index_prefix: Annotated[
            Optional[StrictStr],
            Field(
                description="Only return A/B tests for indices starting with this prefix."
            ),
        ] = None,
        index_suffix: Annotated[
            Optional[StrictStr],
            Field(
                description="Only return A/B tests for indices ending with this suffix."
            ),
        ] = None,
        request_options: Optional[Union[dict, RequestOptions]] = None,
    ) -> ApiResponse[str]:
        """
        List all A/B tests.

        Required API Key ACLs:
          - analytics

        :param offset: Position of the first item to return.
        :type offset: int
        :param limit: Number of items to return.
        :type limit: int
        :param index_prefix: Only return A/B tests for indices starting with this prefix.
        :type index_prefix: str
        :param index_suffix: Only return A/B tests for indices ending with this suffix.
        :type index_suffix: str
        :param request_options: The request options to send along with the query, they will be merged with the transporter base parameters (headers, query params, timeouts, etc.). (optional)
        :return: Returns the raw algoliasearch 'APIResponse' object.
        """

        _query_parameters: List[Tuple[str, str]] = []

        if offset is not None:
            _query_parameters.append(("offset", offset))
        if limit is not None:
            _query_parameters.append(("limit", limit))
        if index_prefix is not None:
            _query_parameters.append(("indexPrefix", index_prefix))
        if index_suffix is not None:
            _query_parameters.append(("indexSuffix", index_suffix))

        return await self._transporter.request(
            verb=Verb.GET,
            path="/2/abtests",
            request_options=self._request_options.merge(
                query_parameters=_query_parameters,
                user_request_options=request_options,
            ),
            use_read_transporter=False,
        )

    async def list_ab_tests(
        self,
        offset: Annotated[
            Optional[Annotated[int, Field(strict=True, ge=0)]],
            Field(description="Position of the first item to return."),
        ] = None,
        limit: Annotated[
            Optional[StrictInt], Field(description="Number of items to return.")
        ] = None,
        index_prefix: Annotated[
            Optional[StrictStr],
            Field(
                description="Only return A/B tests for indices starting with this prefix."
            ),
        ] = None,
        index_suffix: Annotated[
            Optional[StrictStr],
            Field(
                description="Only return A/B tests for indices ending with this suffix."
            ),
        ] = None,
        request_options: Optional[Union[dict, RequestOptions]] = None,
    ) -> ListABTestsResponse:
        """
        List all A/B tests.

        Required API Key ACLs:
          - analytics

        :param offset: Position of the first item to return.
        :type offset: int
        :param limit: Number of items to return.
        :type limit: int
        :param index_prefix: Only return A/B tests for indices starting with this prefix.
        :type index_prefix: str
        :param index_suffix: Only return A/B tests for indices ending with this suffix.
        :type index_suffix: str
        :param request_options: The request options to send along with the query, they will be merged with the transporter base parameters (headers, query params, timeouts, etc.). (optional)
        :return: Returns the deserialized response in a 'ListABTestsResponse' result object.
        """
        return (
            await self.list_ab_tests_with_http_info(
                offset, limit, index_prefix, index_suffix, request_options
            )
        ).deserialize(ListABTestsResponse)

    async def stop_ab_test_with_http_info(
        self,
        id: Annotated[StrictInt, Field(description="Unique A/B test ID.")],
        request_options: Optional[Union[dict, RequestOptions]] = None,
    ) -> ApiResponse[str]:
        """
        If stopped, the test is over and can't be restarted. There is now only one index, receiving 100% of all search requests. The data gathered for stopped A/B tests is retained. To determine the `id` for an A/B test, use the [`listABTests` operation](#tag/abtest/operation/listABTests).

        Required API Key ACLs:
          - editSettings

        :param id: Unique A/B test ID. (required)
        :type id: int
        :param request_options: The request options to send along with the query, they will be merged with the transporter base parameters (headers, query params, timeouts, etc.). (optional)
        :return: Returns the raw algoliasearch 'APIResponse' object.
        """

        if id is None:
            raise ValueError("Parameter `id` is required when calling `stop_ab_test`.")

        return await self._transporter.request(
            verb=Verb.POST,
            path="/2/abtests/{id}/stop".replace("{id}", quote(str(id), safe="")),
            request_options=self._request_options.merge(
                user_request_options=request_options,
            ),
            use_read_transporter=False,
        )

    async def stop_ab_test(
        self,
        id: Annotated[StrictInt, Field(description="Unique A/B test ID.")],
        request_options: Optional[Union[dict, RequestOptions]] = None,
    ) -> ABTestResponse:
        """
        If stopped, the test is over and can't be restarted. There is now only one index, receiving 100% of all search requests. The data gathered for stopped A/B tests is retained. To determine the `id` for an A/B test, use the [`listABTests` operation](#tag/abtest/operation/listABTests).

        Required API Key ACLs:
          - editSettings

        :param id: Unique A/B test ID. (required)
        :type id: int
        :param request_options: The request options to send along with the query, they will be merged with the transporter base parameters (headers, query params, timeouts, etc.). (optional)
        :return: Returns the deserialized response in a 'ABTestResponse' result object.
        """
        return (
            await self.stop_ab_test_with_http_info(id, request_options)
        ).deserialize(ABTestResponse)
