######################################################################################################################
#  Copyright Amazon.com, Inc. 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                                                             #
#                                                                                                                    #
#      http://www.apache.org/licenses/LICENSE-2.0                                                                    #
#                                                                                                                    #
#  or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES #
#  OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions    #
#  and limitations under the License.                                                                                #
######################################################################################################################

import os
from time import sleep
import botocore
from crhelper import CfnResource
from shared.logger import get_logger
from shared.client import get_client
from leave_feedback.intent import create_feedback_intent
from book_appointment.intent import create_appointment_intent
from order_pizza.intent import create_order_pizza_intent
from weather_forecast.intent import create_weather_intent
from other_intents.help_intent import create_help_intent
from other_intents.name_intent import create_name_intent

from shared.helpers import detect_locale, abort_statement

logger = get_logger(__name__)
helper = CfnResource(json_logging=True, log_level="INFO")
client = get_client("lexv2-models")


def wait_for_bot(bot_id):
    response = client.describe_bot(botId=bot_id)
    bot_status = response["botStatus"]
    while bot_status == "Creating":
        sleep(1)
        response = client.describe_bot(botId=bot_id)
        bot_status = response["botStatus"]
    if bot_status != "Available":
        logger.error(response)
        raise RuntimeError("Failed to create Lex bot.")


def wait_for_locale(bot_id, locale_id):
    response = client.describe_bot_locale(
        botId=bot_id, localeId=locale_id, botVersion="DRAFT"
    )
    bot_locale_status = response["botLocaleStatus"]
    while bot_locale_status == "Creating":
        sleep(1)
        response = client.describe_bot_locale(
            botId=bot_id, localeId=locale_id, botVersion="DRAFT"
        )
        bot_locale_status = response["botLocaleStatus"]
    if bot_locale_status == "Failed":
        logger.error(response)
        raise RuntimeError("Failed to create Lex bot locale")


def wait_for_build(bot_id, locale_id):
    response = client.describe_bot_locale(
        botId=bot_id, localeId=locale_id, botVersion="DRAFT"
    )
    bot_locale_status = response["botLocaleStatus"]
    while bot_locale_status == "Building":
        sleep(1)
        response = client.describe_bot_locale(
            botId=bot_id, localeId=locale_id, botVersion="DRAFT"
        )
        bot_locale_status = response["botLocaleStatus"]
    if bot_locale_status == "Failed":
        logger.error(response)
        raise RuntimeError("Failed to create Lex bot locale")

def wait_for_bot_delete(bot_id):
    try:
        response = client.describe_bot(botId=bot_id)
        bot_status = response["botStatus"]
        while bot_status == "Deleting":
            sleep(1)
            response = client.describe_bot(botId=bot_id)
            bot_status = response["botStatus"]
        if bot_status == "Failed":
            logger.error(response)
            raise RuntimeError("Failed to delete Lex bot.")
    except botocore.exceptions.ClientError as error:
        if error.response['Error']['Code'] == 'ResourceNotFoundException':
            logger.info(f"Bot with bot_id {bot_id} successfully deleted.")
        else:
            logger.error(error)
            raise RuntimeError("Failed to delete Lex bot.")

def create_lex_bot_locale(bot_language, bot_id):
    locale_response = client.create_bot_locale(
        botId=bot_id,
        botVersion="DRAFT",
        localeId=detect_locale(bot_language),
        description=f"created {bot_language} from lambda",
        nluIntentConfidenceThreshold=0.4,
    )
    return locale_response


def create_lex_bot(bot_name, bot_role_arn, child_directed):
    bot_response = client.create_bot(
        botName=bot_name,
        description="Created by Serverless Bot Framework",
        roleArn=bot_role_arn,
        dataPrivacy={"childDirected": child_directed == "Yes"},
        idleSessionTTLInSeconds=300,
        botTags={"createdby": "serverless bot framework"},
    )
    return bot_response


def get_bot_alias_id(bot_id):
    alias_response = client.list_bot_aliases(botId=bot_id)
    alias_id = alias_response["botAliasSummaries"][0]["botAliasId"]
    return alias_id

def get_bot_id():
    bot_name = os.environ.get("botName")
    alias_response = client.list_bots(filters=[{
        "name": "BotName",
        "values": [bot_name],
        "operator": "EQ",
    }])
    bot_id = alias_response["botSummaries"][0]["botId"]
    return bot_id


def configure_lex_bot(bot_name, bot_role_arn, child_directed, bot_language):
    # Creating a Lex bot
    bot_response = create_lex_bot(bot_name, bot_role_arn, child_directed)
    logger.info(bot_response)
    bot_id = bot_response["botId"]
    wait_for_bot(bot_id)
    bot_alias_id = get_bot_alias_id(bot_id)

    # Creating a locale for the Lex bot
    locale_response = create_lex_bot_locale(bot_language, bot_id)
    locale_id = locale_response["localeId"]
    wait_for_locale(bot_id, locale_id)
    logger.info(locale_response)

    return bot_id, bot_alias_id, locale_id


def create_bot_intents(bot_id, bot_alias_id, locale_id):
    create_feedback_intent(bot_id, locale_id, bot_alias_id)
    create_appointment_intent(bot_id, locale_id)
    create_order_pizza_intent(bot_id, locale_id)
    create_weather_intent(bot_id, locale_id)
    create_help_intent(bot_id, locale_id)
    create_name_intent(bot_id, locale_id)


def build_lex_bot(bot_id, locale_id):
    # build fully configured bot
    build_response = client.build_bot_locale(
        botId=bot_id, botVersion="DRAFT", localeId=locale_id
    )
    logger.info(build_response)
    # wait for bot to finish building
    wait_for_build(bot_id, locale_id)


@helper.create
def create_resource(event, _):

    # Get environment variables
    bot_language = os.environ.get("botLanguage")
    bot_name = os.environ.get("botName")
    bot_role_arn = os.environ.get("botRole")
    child_directed = os.environ.get("childDirected")

    # Create Lex bot and intents
    bot_id, bot_alias_id, locale_id = configure_lex_bot(
        bot_name, bot_role_arn, child_directed, bot_language
    )
    create_bot_intents(bot_id, bot_alias_id, locale_id)
    build_lex_bot(bot_id, locale_id)

    # Send response to Cloudformation
    helper.Data.update(BotId=bot_id, BotAliasId=bot_alias_id)
    return bot_id


@helper.delete
def delete_resource(event, _):
    try:
        logger.info(event)
        bot_id = get_bot_id()
        response = client.delete_bot(botId=bot_id, skipResourceInUseCheck=True)
        logger.info(response)

    except Exception as e:
        logger.error(e)
        raise RuntimeError("Failed to delete Bot.")

@helper.update
def update_resource(event, _):
    delete_resource(event, _)
    bot_id = get_bot_id()
    wait_for_bot_delete(bot_id)
    create_resource(event, _)

def handler(event, context):
    helper(event, context)

######################################################################################################################
#  Copyright Amazon.com, Inc. 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                                                             #
#                                                                                                                    #
#      http://www.apache.org/licenses/LICENSE-2.0                                                                    #
#                                                                                                                    #
#  or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES #
#  OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions    #
#  and limitations under the License.                                                                                #
######################################################################################################################

import os
from time import sleep
import botocore
from crhelper import CfnResource
from shared.logger import get_logger
from shared.client import get_client
from leave_feedback.intent import create_feedback_intent
from book_appointment.intent import create_appointment_intent
from order_pizza.intent import create_order_pizza_intent
from weather_forecast.intent import create_weather_intent
from other_intents.help_intent import create_help_intent
from other_intents.name_intent import create_name_intent

from shared.helpers import detect_locale, abort_statement

logger = get_logger(__name__)
helper = CfnResource(json_logging=True, log_level="INFO")
client = get_client("lexv2-models")


def wait_for_bot(bot_id):
    response = client.describe_bot(botId=bot_id)
    bot_status = response["botStatus"]
    while bot_status == "Creating":
        sleep(1)
        response = client.describe_bot(botId=bot_id)
        bot_status = response["botStatus"]
    if bot_status != "Available":
        logger.error(response)
        raise RuntimeError("Failed to create Lex bot.")


def wait_for_locale(bot_id, locale_id):
    response = client.describe_bot_locale(
        botId=bot_id, localeId=locale_id, botVersion="DRAFT"
    )
    bot_locale_status = response["botLocaleStatus"]
    while bot_locale_status == "Creating":
        sleep(1)
        response = client.describe_bot_locale(
            botId=bot_id, localeId=locale_id, botVersion="DRAFT"
        )
        bot_locale_status = response["botLocaleStatus"]
    if bot_locale_status == "Failed":
        logger.error(response)
        raise RuntimeError("Failed to create Lex bot locale")


def wait_for_build(bot_id, locale_id):
    response = client.describe_bot_locale(
        botId=bot_id, localeId=locale_id, botVersion="DRAFT"
    )
    bot_locale_status = response["botLocaleStatus"]
    while bot_locale_status == "Building":
        sleep(1)
        response = client.describe_bot_locale(
            botId=bot_id, localeId=locale_id, botVersion="DRAFT"
        )
        bot_locale_status = response["botLocaleStatus"]
    if bot_locale_status == "Failed":
        logger.error(response)
        raise RuntimeError("Failed to create Lex bot locale")

def wait_for_bot_delete(bot_id):
    try:
        response = client.describe_bot(botId=bot_id)
        bot_status = response["botStatus"]
        while bot_status == "Deleting":
            sleep(1)
            response = client.describe_bot(botId=bot_id)
            bot_status = response["botStatus"]
        if bot_status == "Failed":
            logger.error(response)
            raise RuntimeError("Failed to delete Lex bot.")
    except botocore.exceptions.ClientError as error:
        if error.response['Error']['Code'] == 'ResourceNotFoundException':
            logger.info(f"Bot with bot_id {bot_id} successfully deleted.")
        else:
            logger.error(error)
            raise RuntimeError("Failed to delete Lex bot.")

def create_lex_bot_locale(bot_language, bot_id):
    locale_response = client.create_bot_locale(
        botId=bot_id,
        botVersion="DRAFT",
        localeId=detect_locale(bot_language),
        description=f"created {bot_language} from lambda",
        nluIntentConfidenceThreshold=0.4,
    )
    return locale_response


def create_lex_bot(bot_name, bot_role_arn, child_directed):
    bot_response = client.create_bot(
        botName=bot_name,
        description="Created by Serverless Bot Framework",
        roleArn=bot_role_arn,
        dataPrivacy={"childDirected": child_directed == "Yes"},
        idleSessionTTLInSeconds=300,
        botTags={"createdby": "serverless bot framework"},
    )
    return bot_response


def get_bot_alias_id(bot_id):
    alias_response = client.list_bot_aliases(botId=bot_id)
    alias_id = alias_response["botAliasSummaries"][0]["botAliasId"]
    return alias_id

def get_bot_id():
    bot_name = os.environ.get("botName")
    alias_response = client.list_bots(filters=[{
        "name": "BotName",
        "values": [bot_name],
        "operator": "EQ",
    }])
    bot_id = alias_response["botSummaries"][0]["botId"]
    return bot_id


def configure_lex_bot(bot_name, bot_role_arn, child_directed, bot_language):
    # Creating a Lex bot
    bot_response = create_lex_bot(bot_name, bot_role_arn, child_directed)
    logger.info(bot_response)
    bot_id = bot_response["botId"]
    wait_for_bot(bot_id)
    bot_alias_id = get_bot_alias_id(bot_id)

    # Creating a locale for the Lex bot
    locale_response = create_lex_bot_locale(bot_language, bot_id)
    locale_id = locale_response["localeId"]
    wait_for_locale(bot_id, locale_id)
    logger.info(locale_response)

    return bot_id, bot_alias_id, locale_id


def create_bot_intents(bot_id, bot_alias_id, locale_id):
    create_feedback_intent(bot_id, locale_id, bot_alias_id)
    create_appointment_intent(bot_id, locale_id)
    create_order_pizza_intent(bot_id, locale_id)
    create_weather_intent(bot_id, locale_id)
    create_help_intent(bot_id, locale_id)
    create_name_intent(bot_id, locale_id)


def build_lex_bot(bot_id, locale_id):
    # build fully configured bot
    build_response = client.build_bot_locale(
        botId=bot_id, botVersion="DRAFT", localeId=locale_id
    )
    logger.info(build_response)
    # wait for bot to finish building
    wait_for_build(bot_id, locale_id)


@helper.create
def create_resource(event, _):

    # Get environment variables
    bot_language = os.environ.get("botLanguage")
    bot_name = os.environ.get("botName")
    bot_role_arn = os.environ.get("botRole")
    child_directed = os.environ.get("childDirected")

    # Create Lex bot and intents
    bot_id, bot_alias_id, locale_id = configure_lex_bot(
        bot_name, bot_role_arn, child_directed, bot_language
    )
    create_bot_intents(bot_id, bot_alias_id, locale_id)
    build_lex_bot(bot_id, locale_id)

    # Send response to Cloudformation
    helper.Data.update(BotId=bot_id, BotAliasId=bot_alias_id)
    return bot_id


@helper.delete
def delete_resource(event, _):
    try:
        logger.info(event)
        bot_id = get_bot_id()
        response = client.delete_bot(botId=bot_id, skipResourceInUseCheck=True)
        logger.info(response)

    except Exception as e:
        logger.error(e)
        raise RuntimeError("Failed to delete Bot.")

@helper.update
def update_resource(event, _):
    delete_resource(event, _)
    bot_id = get_bot_id()
    wait_for_bot_delete(bot_id)
    create_resource(event, _)

def handler(event, context):
    helper(event, context)

###################################################################################################################### #  Copyright Amazon.com, Inc. 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                                                             # #                                                                                                                    # #      http://www.apache.org/licenses/LICENSE-2.0                                                                    # #                                                                                                                    # #  or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES # #  OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions    # #  and limitations under the License.                                                                                # ###################################################################################################################### # Creating a Lex bot # Creating a locale for the Lex bot # build fully configured bot # wait for bot to finish building # Get environment variables # Create Lex bot and intents # Send response to Cloudformation