#
# # Copyright © 2024 Peak AI Limited. or its affiliates. All Rights Reserved.
# #
# # Licensed under the Apache License, Version 2.0 (the "License"). You
# # may not use this file except in compliance with the License. A copy of
# # the License is located at:
# #
# # https://github.com/PeakBI/peak-sdk/blob/main/LICENSE
# #
# # or in the "license" file accompanying this file. This file is
# # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
# # ANY KIND, either express or implied. See the License for the specific
# # language governing permissions and limitations under the License.
# #
# # This file is part of the peak-sdk.
# # see (https://github.com/PeakBI/peak-sdk)
# #
# # You should have received a copy of the APACHE LICENSE, VERSION 2.0
# # along with this program. If not, see <https://apache.org/licenses/LICENSE-2.0>
#

"""Webapp client module.

.. warning::
    The ``Webapp`` module is deprecated and will eventually be removed. It is recommended that users begin transitioning to the ``Service`` module, which offers all the features of ``Webapp`` along with the added capability of API deployment and other significant updates for enhanced functionality. Transitioning early to the ``Service`` module will ensure easier adoption of its advanced features and future updates.

    For guidance on migrating to the ``Service`` module and taking full advantage of its capabilities, please refer to the ``Service`` module's documentation.
"""
from __future__ import annotations

from typing import Any, Dict, Iterator, List, Literal, Optional, overload

from peak.base_client import BaseClient
from peak.constants import ContentType, HttpMethods
from peak.session import Session


class Webapp(BaseClient):
    """Client class for interacting with webapps resource."""

    BASE_ENDPOINT = "webapps/api/v1"

    @overload
    def list_webapps(
        self,
        page_size: Optional[int] = None,
        page_number: Optional[int] = None,
        status: Optional[List[str]] = None,
        name: Optional[str] = None,
        *,
        return_iterator: Literal[False],
    ) -> Dict[str, Any]: ...

    @overload
    def list_webapps(
        self,
        page_size: Optional[int] = None,
        page_number: Optional[int] = None,
        status: Optional[List[str]] = None,
        name: Optional[str] = None,
        *,
        return_iterator: Literal[True] = True,
    ) -> Iterator[Dict[str, Any]]: ...

    def list_webapps(
        self,
        page_size: Optional[int] = None,
        page_number: Optional[int] = None,
        status: Optional[List[str]] = None,
        name: Optional[str] = None,
        *,
        return_iterator: bool = True,
    ) -> Iterator[Dict[str, Any]] | Dict[str, Any]:
        """Retrieve a list of webapps.

        REFERENCE:
            🔗 `API Documentation <https://service.peak.ai/webapps/api-docs/index.htm#/Services/list-service>`__

        Args:
            page_size (int | None): The number of webapps per page.
            page_number (int | None): The page number to retrieve. Only used when `return_iterator` is False.
            status (List[str] | None): A list of webapp status to filter the list by.
                Valid values are `CREATING`, `DEPLOYING`, `AVAILABLE`, `DELETING`, `CREATE_FAILED`, `DELETE_FAILED`.
            name (str | None): Name of the webapp to search for.
            return_iterator (bool): Whether to return an iterator object or list of webapps for a specified page number, defaults to True.

        Returns:
            Iterator[Dict[str, Any] | Dict[str, Any]: an iterator object which returns an element per iteration, until there are no more elements to return.
            If `return_iterator` is set to False, a dictionary containing the list and pagination details is returned instead.
            Set `return_iterator` to True if you want automatic client-side pagination, or False if you want server-side pagination.

        Raises:
            BadRequestException: The given request parameters are invalid.
            UnauthorizedException: The credentials are invalid.
            ForbiddenException: The user does not have permission to perform the operation.
            InternalServerErrorException: The server failed to process the request.
        """
        method, endpoint = HttpMethods.GET, f"{self.BASE_ENDPOINT}/webapps/"
        params = {"pageSize": page_size, "status": status, "searchTerm": name}

        if return_iterator:
            return self.session.create_generator_request(
                endpoint,
                method,
                content_type=ContentType.APPLICATION_JSON,
                response_key="webapps",
                params=params,
            )

        return self.session.create_request(  # type: ignore[no-any-return]
            endpoint,
            method,
            content_type=ContentType.APPLICATION_JSON,
            params={**params, "pageNumber": page_number},
        )

    def create_webapp(self, body: Dict[str, Any]) -> Dict[str, str]:
        """Create a new webapp. Only geneic (EKS-based) webapps are supported at the moment.

        REFERENCE:
            🔗 `API Documentation <https://service.peak.ai/webapps/api-docs/index.htm#/Services/create-service>`__

        Args:
            body (Dict[str, Any]): A dictionary containing the webapp config. Schema can be found below.

        Returns:
            Dict[str, str]: Id of the new webapp

        SCHEMA:
            .. code-block:: json

                {
                    "name": "string(required)",
                    "title": "string",
                    "imageDetails": {
                        "imageId": "number(required)",
                        "versionId": "number",
                    },
                    "resources": {
                        "instanceTypeId": "number"
                    },
                    "description": "string",
                    "sessionStickiness": "boolean"
                }

        Raises:
            BadRequestException: The given request parameters are invalid.
            UnauthorizedException: The credentials are invalid.
            ForbiddenException: The user does not have permission to perform the operation.
            InternalServerErrorException: The server failed to process the request.
        """
        method, endpoint = HttpMethods.POST, f"{self.BASE_ENDPOINT}/webapps/"

        return self.session.create_request(  # type: ignore[no-any-return]
            endpoint,
            method,
            content_type=ContentType.APPLICATION_JSON,
            body=body,
        )

    def update_webapp(
        self,
        webapp_id: str,
        body: Dict[str, Any],
    ) -> Dict[str, str]:
        """Updates the existing webapp. Only geneic (EKS-based) webapps are supported at the moment.

        When updating the webapp, it will trigger a redeployment only under specific conditions.
        Redeployment is triggered if you make changes to any of the following parameters: imageId, versionId, instanceTypeId or sessionStickiness.
        However, only modifying the title or description will not trigger a redeployment.

        REFERENCE:
            🔗 `API Documentation <https://service.peak.ai/webapps/api-docs/index.htm#/Services/update-service>`__

        Args:
            webapp_id (str): The ID of the webapp to update.
            body (Dict[str, Any]): A dictionary containing the webapp config. Schema can be found below.

        Returns:
            Dict[str, str]: Id of the webapp.

        SCHEMA:
            .. code-block:: json

                {
                    "title": "string",
                    "imageDetails": {
                        "imageId": "number(required)",
                        "versionId": "number",
                    },
                    "resources": {
                        "instanceTypeId": "number"
                    },
                    "description": "string",
                    "sessionStickiness": "boolean"
                }

        Raises:
            BadRequestException: The given request parameters are invalid.
            UnauthorizedException: The credentials are invalid.
            ForbiddenException: The user does not have permission to perform the operation.
            NotFoundException: The given webapp does not exist.
            UnprocessableEntityException: The server was unable to process the request.
            InternalServerErrorException: The server failed to process the request.
        """
        method, endpoint = HttpMethods.PATCH, f"{self.BASE_ENDPOINT}/webapps/{webapp_id}"
        return self.session.create_request(  # type: ignore[no-any-return]
            endpoint,
            method,
            content_type=ContentType.APPLICATION_JSON,
            body=body,
        )

    def create_or_update_webapp(self, body: Dict[str, Any]) -> Dict[str, str]:
        """Create a new webapp or updates an existing webapp based on webapp name.

        When updating the webapp, it will trigger a redeployment only under specific conditions.
        Redeployment is triggered if you make changes to any of the following parameters: imageId, versionId, instanceTypeId or sessionStickiness.
        However, only modifying the title or description will not trigger a redeployment.

        REFERENCE:
            🔗 `API Documentation <https://service.peak.ai/webapps/api-docs/index.htm#/Services/create-service>`__

        Args:
            body (Dict[str, Any]): A dictionary containing the webapp config. Schema can be found below.

        Returns:
            Dict[str, str]: Id of the new or updated webapp.

        SCHEMA:
            .. code-block:: json

                {
                    "name": "string(required)",
                    "title": "string",
                    "imageDetails": {
                        "imageId": "number(required)",
                        "versionId": "number"
                    },
                    "resources": {
                        "instanceTypeId": "number"
                    },
                    "description": "string",
                    "sessionStickiness": "boolean"
                }


        Raises:
            BadRequestException: The given request parameters are invalid.
            UnauthorizedException: The credentials are invalid.
            ForbiddenException: The user does not have permission to perform the operation.
            InternalServerErrorException: The server failed to process the request.
        """
        webapp_name = body.get("name", "")
        response = (
            {} if not len(webapp_name) else self.list_webapps(page_size=100, return_iterator=False, name=webapp_name)
        )
        filtered_webapps = list(
            filter(lambda webapp: webapp.get("name", "") == webapp_name, response.get("webapps", [])),
        )

        if len(filtered_webapps) > 0:
            webapp_id = filtered_webapps[0]["id"]
            return self.update_webapp(webapp_id=webapp_id, body=body)

        return self.create_webapp(body=body)

    def delete_webapp(
        self,
        webapp_id: str,
    ) -> Dict[str, str]:
        """Delete a webapp.

        REFERENCE:
            🔗 `API Documentation <https://service.peak.ai/webapps/api-docs/index.htm#/Services/delete-service>`__

        Args:
            webapp_id (str): The ID of the webapp to delete.

        Returns:
            Dict[str, str]: Dictonary containing Id of the deleted webapp

        Raises:
            UnauthorizedException: The credentials are invalid.
            ForbiddenException: The user does not have permission to perform the operation.
            NotFoundException: The given webapp does not exist.
            ConflictException: If the webapp is in a conflicting state while deleting.
            InternalServerErrorException: The server failed to process the request.
        """
        method, endpoint = HttpMethods.DELETE, f"{self.BASE_ENDPOINT}/webapps/{webapp_id}"

        return self.session.create_request(  # type: ignore[no-any-return]
            endpoint,
            method,
            content_type=ContentType.APPLICATION_JSON,
        )

    def describe_webapp(
        self,
        webapp_id: str,
    ) -> Dict[str, Any]:
        """Retrieve details of a specific webapp.

        REFERENCE:
            🔗 `API Documentation <https://service.peak.ai/webapps/api-docs/index.htm#/Services/get-service>`__

        Args:
            webapp_id (str): The ID of the webapp to fetch.

        Returns:
            Dict[str, Any]: Dictonary containing details of the webapp

        Raises:
            UnauthorizedException: The credentials are invalid.
            ForbiddenException: The user does not have permission to perform the operation.
            NotFoundException: The given webapp does not exist.
            UnprocessableEntityException: The server was unable to process the request.
            InternalServerErrorException: The server failed to process the request.
        """
        method, endpoint = HttpMethods.GET, f"{self.BASE_ENDPOINT}/webapps/{webapp_id}"

        return self.session.create_request(  # type: ignore[no-any-return]
            endpoint,
            method,
            content_type=ContentType.APPLICATION_JSON,
        )


def get_client(session: Optional[Session] = None) -> Webapp:
    """Returns a Webapp client, If no session is provided, a default session is used.

    Args:
        session (Optional[Session]): A Session Object. Default is None.

    Returns:
        Webapp: the webapp client object
    """
    return Webapp(session)


__all__ = ["get_client"]
