#
# # 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>
#

#

"""Peak Webapps commands.

.. warning::
    The ``Web Apps`` commands are deprecated and will eventually be removed. It is recommended that users begin transitioning to the ``Service`` commands, 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`` commands will ensure easier adoption of its advanced features and future updates.

    For guidance on migrating to the ``Service`` and taking full advantage of its capabilities, please refer to the ``Service`` documentation.
"""

from typing import Any, Dict, List, Optional

import typer
from peak.cli import args, helpers
from peak.cli.args import DRY_RUN, GENERATE_YAML, OUTPUT_TYPES, PAGING
from peak.constants import OutputTypes, OutputTypesNoTable
from peak.helpers import combine_dictionaries, map_user_options, parse_list_of_strings, variables_to_dict
from peak.output import Writer
from peak.resources.webapps import Webapp
from typing_extensions import Annotated

app = typer.Typer(
    help="""Visualize your data and predictions using Webapps.
    ```yaml
    NOTE: Please note that only generic (EKS-based) webapps are supported with CLI. **Note** that, the functionalities provided through the `Webapp` feature are deprecated and will eventually be removed. We recommend using the `Service` feature which offers a more comprehensive and flexible solution for managing web applications and API deployments.
    ```
    """,
    short_help="Create and Manage Webapps.",
)

_WEBAPP_ID = typer.Argument(..., help="ID of the webapp to be used in this operation")

_LIST_STATUS = typer.Option(
    None,
    help="A list of webapp status to filter the list by. Valid values are `CREATING`, `DEPLOYING`, `AVAILABLE`, `DELETING`, `CREATE_FAILED`, `DELETE_FAILED`.",
)

_LIST_NAME = typer.Option(None, help="Webapp name to search for")

FILE_HELP_STRING = (
    "Path to the file that defines the body for this operation, supports both `yaml` file or a `jinja` template."
)

NAME = typer.Option(None, help="Name of the webapp")

DESCRIPTION = typer.Option(None, help="Description of the webapp")

TITLE = typer.Option(None, help="Title of the webapp")

IMAGE_ID = typer.Option(None, help="ID of the image to be used in this operation.")

VERSION_ID = typer.Option(
    None,
    help="ID of the version to be used in this operation. If version-id is not passed, webapp will be created using latest ready version of the image.",
)

INSTANCE_TYPE_ID = typer.Option(None, help="The ID of the instance type to be used in this operation.")

SESSION_STICKINESS = typer.Option(None, help="Enable session stickiness for the webapp.")

MAPPING = {"imageId": "imageDetails", "versionId": "imageDetails", "instanceTypeId": "resources"}

DEPRECATION_MESSAGE = "The Web App commands are deprecated and will eventually be removed. We recommend using the Service feature which offers a more comprehensive and flexible solution for managing web applications and API deployments.\n"


@app.command("list", short_help="List webapps.")
def list_webapps(
    ctx: typer.Context,
    page_size: Optional[int] = args.PAGE_SIZE,
    page_number: Optional[int] = args.PAGE_NUMBER,
    status: Optional[List[str]] = _LIST_STATUS,
    name: Optional[str] = _LIST_NAME,
    paging: Optional[bool] = PAGING,  # noqa: ARG001
    output_type: Optional[OutputTypes] = OUTPUT_TYPES,  # noqa: ARG001
) -> None:
    """***List*** all webapps that exist for the tenant.

    \b
     ```yaml
    NOTE: The Web Apps commands are deprecated and will eventually be removed. It is recommended that users begin transitioning to the Service commands, 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 commands will ensure easier adoption of its advanced features and future updates.
    ```

    \b
    For more information on Services, please refer to the [**Service**](https://docs.peak.ai/sdk/latest/cli/reference.html#peak-services) documentation.

    \b
    📝 ***Example usage:***<br/>
    ```bash
    peak webapps list --page-size 10 --page-number 1 --status CREATING --name test
    ```

    \b
    🆗 ***Response:***
    ```
    {
        "webappsCount": 1,
        "webapps": [...],
        "pageCount": 1,
        "pageNumber": 1,
        "pageSize": 25
    }
    ```

    🔗 [**API Documentation**](https://service.peak.ai/webapps/api-docs/index.htm#/Services/list-service)
    """
    webapp_client: Webapp = ctx.obj["client"]
    writer: Writer = ctx.obj["writer"]

    with writer.pager():
        response = webapp_client.list_webapps(
            page_size=page_size,
            page_number=page_number,
            return_iterator=False,
            status=parse_list_of_strings(status),
            name=name,
        )
        writer.write(response, deprecation_message=DEPRECATION_MESSAGE)


@app.command(short_help="Create a new webapp.")
def create(
    ctx: typer.Context,
    file: Annotated[Optional[str], typer.Argument(..., help=FILE_HELP_STRING)] = None,
    params_file: str = args.TEMPLATE_PARAMS_FILE,
    params: List[str] = args.TEMPLATE_PARAMS,
    name: str = NAME,
    title: str = TITLE,
    description: str = DESCRIPTION,
    image_id: int = IMAGE_ID,
    version_id: int = VERSION_ID,
    instance_type_id: int = INSTANCE_TYPE_ID,
    session_stickiness: bool = SESSION_STICKINESS,
    dry_run: Optional[bool] = DRY_RUN,  # noqa: ARG001
    paging: Optional[bool] = PAGING,  # noqa: ARG001
    output_type: Optional[OutputTypesNoTable] = OUTPUT_TYPES,  # noqa: ARG001
    generate: Optional[bool] = GENERATE_YAML,  # noqa: ARG001
) -> None:
    """***Create*** a new webapp and start its deployment.

    \b
     ```yaml
    NOTE: The Web Apps commands are deprecated and will eventually be removed. It is recommended that users begin transitioning to the Service commands, 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 commands will ensure easier adoption of its advanced features and future updates.
    ```

    \b
    For more information on Services, please refer to the [**Service**](https://docs.peak.ai/sdk/latest/cli/reference.html#peak-services) documentation.

    \b
    🧩 ***Input file schema(yaml):***<br/>
    ```yaml
      body (map):
        name (string): Name of the webapp.
        title (string | required: false): Title of the webapp.
        description (string | required: false): Description of the webapp.
        imageDetails (map):
            imageId (number): ID of the image.
            versionId (number | required: false): ID of the image version. If versionId is not passed, webapp will be created using latest ready version of the image.
        resources (map | required: false):
            instanceTypeId (number): ID of the instance type.
        sessionStickiness (boolean | required: false): Enable session stickiness for the webapp. Default value is false. Enabling session stickiness will tie each user to a specific server for all their requests.
    ```

    \b
    📝 ***Example usage:***
    ```bash
    peak webapps create '/path/to/file.yml' -v '/path/to/params.yml'
    ```

    \b
    📝 ***Example usage without yaml:***
    ```bash
    peak webapps create --name <name> --title <title> --description <description> --image-id <image-id> --version-id <version-id> --instance-type-id <instance-type-id> --session-stickiness
    ```

    \b
    🆗 ***Response:***
    ```json
    {
        "id": "db88c21d-1add-45dd-a72e-8c6b83b68dee"
    }
    ```

    🔗 [**API Documentation**](https://service.peak.ai/webapps/api-docs/index.htm#/Services/create-service)
    """
    webapp_client: Webapp = ctx.obj["client"]
    writer: Writer = ctx.obj["writer"]

    user_options: Dict[str, Any] = variables_to_dict(
        name,
        description,
        title,
        image_id,
        version_id,
        instance_type_id,
        session_stickiness,
    )
    user_options = map_user_options(user_options, MAPPING)

    body: Dict[str, Any] = {}
    if file:
        body = helpers.template_handler(file=file, params_file=params_file, params=params)
        body = helpers.remove_unknown_args(body, webapp_client.create_webapp)

    body = combine_dictionaries(body.get("body") or {}, user_options)

    with writer.pager():
        response = webapp_client.create_webapp(body=body)
        writer.write(response, deprecation_message=DEPRECATION_MESSAGE)


@app.command(short_help="Update an existing webapp.")
def update(
    ctx: typer.Context,
    webapp_id: str = _WEBAPP_ID,
    file: Annotated[Optional[str], typer.Argument(..., help=FILE_HELP_STRING)] = None,
    params_file: str = args.TEMPLATE_PARAMS_FILE,
    params: List[str] = args.TEMPLATE_PARAMS,
    title: str = TITLE,
    description: str = DESCRIPTION,
    image_id: int = IMAGE_ID,
    version_id: int = VERSION_ID,
    instance_type_id: int = INSTANCE_TYPE_ID,
    session_stickiness: bool = SESSION_STICKINESS,
    dry_run: Optional[bool] = DRY_RUN,  # noqa: ARG001
    paging: Optional[bool] = PAGING,  # noqa: ARG001
    output_type: Optional[OutputTypesNoTable] = OUTPUT_TYPES,  # noqa: ARG001
    generate: Optional[bool] = GENERATE_YAML,  # noqa: ARG001
) -> None:
    """***Update*** an existing webapp.

    \b
     ```yaml
    NOTE: The Web Apps commands are deprecated and will eventually be removed. It is recommended that users begin transitioning to the Service commands, 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 commands will ensure easier adoption of its advanced features and future updates.
    ```

    \b
    For more information on Services, please refer to the [**Service**](https://docs.peak.ai/sdk/latest/cli/reference.html#peak-services) documentation.

    \b
    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.

    \b
    🧩 ***Input file schema(yaml):***<br/>
    ```yaml
      body (map):
        title (string | required: false): Title of the webapp.
        description (string | required: false): Description of the webapp.
        imageDetails (map | required: false):
            imageId (number): ID of the image.
            versionId (number | required: false): ID of the image version. If versionId is not passed, webapp will be created using latest ready version of the image.
        resources (map | required: false):
            instanceTypeId (number): ID of the instance type.
        sessionStickiness (boolean | required: false): Enable session stickiness for the webapp. Default value is false. Enabling session stickiness will tie each user to a specific server for all their requests.
    ```

    \b
    📝 ***Example usage:***
    ```bash
    peak webapps update <webapp-id> '/path/to/file.yml' -v '/path/to/params.yml'
    ```

     \b
    📝 ***Example usage without yaml:***
    ```bash
    peak webapps update <webapp-id> --title <title> --description <description> --image-id <image-id> --version-id <version-id> --instance-type-id <instance-type-id> --session-stickiness
    ```

    \b
    🆗 ***Response:***
    ```json
    {
        "id": "ab11c21d-1add-45dd-a72e-8c6b83b68dee"
    }
    ```

    🔗 [**API Documentation**](https://service.peak.ai/webapps/api-docs/index.htm#/Services/update-service)
    """
    webapp_client: Webapp = ctx.obj["client"]
    writer: Writer = ctx.obj["writer"]

    user_options: Dict[str, Any] = variables_to_dict(
        description,
        title,
        image_id,
        version_id,
        instance_type_id,
        session_stickiness,
    )
    user_options = map_user_options(user_options, MAPPING)

    body: Dict[str, Any] = {}
    if file:
        body = helpers.template_handler(file=file, params_file=params_file, params=params)
        body = helpers.remove_unknown_args(body, webapp_client.update_webapp)
    body = combine_dictionaries(body.get("body") or {}, user_options)

    with writer.pager():
        response = webapp_client.update_webapp(webapp_id=webapp_id, body=body)
        writer.write(response, deprecation_message=DEPRECATION_MESSAGE)


@app.command(short_help="Create a new webapp or Update an existing webapp.")
def create_or_update(
    ctx: typer.Context,
    file: Annotated[Optional[str], typer.Argument(..., help=FILE_HELP_STRING)] = None,
    params_file: str = args.TEMPLATE_PARAMS_FILE,
    params: List[str] = args.TEMPLATE_PARAMS,
    name: str = NAME,
    title: str = TITLE,
    description: str = DESCRIPTION,
    image_id: int = IMAGE_ID,
    version_id: int = VERSION_ID,
    instance_type_id: int = INSTANCE_TYPE_ID,
    session_stickiness: bool = SESSION_STICKINESS,
    output_type: Optional[OutputTypesNoTable] = OUTPUT_TYPES,  # noqa: ARG001
    generate: Optional[bool] = GENERATE_YAML,  # noqa: ARG001
) -> None:
    """***Create*** a new webapp or ***Update*** an existing webapp based on webapp name and start its deployment.

    \b
     ```yaml
    NOTE: The Web Apps commands are deprecated and will eventually be removed. It is recommended that users begin transitioning to the Service commands, 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 commands will ensure easier adoption of its advanced features and future updates.
    ```

    \b
    For more information on Services, please refer to the [**Service**](https://docs.peak.ai/sdk/latest/cli/reference.html#peak-services) documentation.

    \b
    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.

    \b
    🧩 ***Input file schema(yaml):***<br/>
    ```yaml
      body (map):
        name (string): Name of the webapp.
        title (string | required: false): Title of the webapp.
        description (string | required: false): Description of the webapp.
        imageDetails (map):
            imageId (number): ID of the image.
            versionId (number | required: false): ID of the image version. If versionId is not passed, webapp will be created using latest ready version of the image.
        resources (map | required: false):
            instanceTypeId (number): ID of the instance type.
        sessionStickiness (boolean | required: false): Enable session stickiness for the webapp. Default value is false. Enabling session stickiness will tie each user to a specific server for all their requests.
    ```

    \b
    📝 ***Example usage:***
    ```bash
    peak webapps create-or-update '/path/to/file.yml' -v '/path/to/params.yml'
    ```

    \b
    📝 ***Example usage without yaml:***
    ```bash
    peak webapps create-or-update --name <name> --title <title> --description <description> --image-id <image-id> --version-id <version-id> --instance-type-id <instance-type-id> --session-stickiness
    ```

    \b
    🆗 ***Response:***
    ```json
    {
        "id": "db88c21d-1add-45dd-a72e-8c6b83b68dee"
    }
    ```

    🔗 [**API Documentation**](https://service.peak.ai/webapps/api-docs/index.htm#/Services/create-service)
    """
    webapp_client: Webapp = ctx.obj["client"]
    writer: Writer = ctx.obj["writer"]

    user_options: Dict[str, Any] = variables_to_dict(
        name,
        description,
        title,
        image_id,
        version_id,
        instance_type_id,
        session_stickiness,
    )
    user_options = map_user_options(user_options, MAPPING)

    body: Dict[str, Any] = {}
    if file:
        body = helpers.template_handler(file=file, params_file=params_file, params=params)
        body = helpers.remove_unknown_args(body, webapp_client.create_or_update_webapp)

    body = combine_dictionaries(body.get("body") or {}, user_options)

    response = webapp_client.create_or_update_webapp(body=body)
    writer.write(response, deprecation_message=DEPRECATION_MESSAGE)


@app.command(short_help="Delete an existing webapp.")
def delete(
    ctx: typer.Context,
    webapp_id: str = _WEBAPP_ID,
    dry_run: Optional[bool] = DRY_RUN,  # noqa: ARG001
    paging: Optional[bool] = PAGING,  # noqa: ARG001
    output_type: Optional[OutputTypesNoTable] = OUTPUT_TYPES,  # noqa: ARG001
) -> None:
    """***Delete*** an existing webapp.

    \b
     ```yaml
    NOTE: The Web Apps commands are deprecated and will eventually be removed. It is recommended that users begin transitioning to the Service commands, 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 commands will ensure easier adoption of its advanced features and future updates.
    ```

    \b
    For more information on Services, please refer to the [**Service**](https://docs.peak.ai/sdk/latest/cli/reference.html#peak-services) documentation.

    \b
    📝 ***Example usage:***<br/>
    ```bash
    peak webapps delete "ab11c21d-1add-45dd-a72e-8c6b83b68dee"
    ```

    \b
    🆗 ***Response:***
    ```json
    {
        "id": "ab11c21d-1add-45dd-a72e-8c6b83b68dee"
    }
    ```

    🔗 [**API Documentation**](https://service.peak.ai/webapps/api-docs/index.htm#/Services/delete-service)
    """
    webapp_client: Webapp = ctx.obj["client"]
    writer: Writer = ctx.obj["writer"]

    with writer.pager():
        response = webapp_client.delete_webapp(webapp_id=webapp_id)
        writer.write(response, deprecation_message=DEPRECATION_MESSAGE)


@app.command(short_help="Describe details of a webapp.")
def describe(
    ctx: typer.Context,
    webapp_id: str = _WEBAPP_ID,
    paging: Optional[bool] = PAGING,  # noqa: ARG001
    output_type: Optional[OutputTypesNoTable] = OUTPUT_TYPES,  # noqa: ARG001
) -> None:
    """***Describe*** details for the specific webapp.

    \b
     ```yaml
    NOTE: The Web Apps commands are deprecated and will eventually be removed. It is recommended that users begin transitioning to the Service commands, 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 commands will ensure easier adoption of its advanced features and future updates.
    ```

    \b
    For more information on Services, please refer to the [**Service**](https://docs.peak.ai/sdk/latest/cli/reference.html#peak-services) documentation.

    \b
    📝 ***Example usage:***<br/>
    ```bash
    peak webapps describe "ab11c21d-1add-45dd-a72e-8c6b83b68dee"
    ```

    \b
    🆗 ***Response:***
    ```
    {
        "id": "ab11c21d-1add-45dd-a72e-8c6b83b68dee",
        "name": "awesome-webapp",
        "status": "AVAILABLE",
        "imageDetails": {
            "imageId": 1,
            "versionId": 1
        },
        "resources": {
            "instanceTypeId": 1
        },
        "sessionStickiness": false,
        "createdAt": "2020-01-01T18:00:00.000Z",
        "createdBy": "someone@peak.ai",
        "updatedAt": "2020-01-01T18:00:00.000Z",
        "updatedBy": "someone@peak.ai",
        "tags": [...]
    }
    ```

    🔗 [**API Documentation**](https://service.peak.ai/webapps/api-docs/index.htm#/Services/get-service)
    """
    webapp_client: Webapp = ctx.obj["client"]
    writer: Writer = ctx.obj["writer"]

    with writer.pager():
        response = webapp_client.describe_webapp(webapp_id=webapp_id)
        writer.write(response, deprecation_message=DEPRECATION_MESSAGE)
