# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

from typing import List

from datatypes_date_time.timex import Timex

from botbuilder.dialogs import WaterfallDialog, WaterfallStepContext, DialogTurnResult
from botbuilder.dialogs.prompts import ConfirmPrompt, TextPrompt, PromptOptions
from botbuilder.core import MessageFactory
from botbuilder.schema import InputHints

from helpers.luis_helper import LuisHelper
from user_profile import UserProfile
from .cancel_and_help_dialog import CancelAndHelpDialog
import os
import json
from botbuilder.schema import Attachment, ChannelAccount
from botbuilder.schema import ChannelAccount, CardAction, ActionTypes, SuggestedActions
from botbuilder.dialogs.prompts import ConfirmPrompt, ChoicePrompt, PromptOptions
from botbuilder.dialogs.choices import Choice
from botbuilder.dialogs.choices import Choice
from botbuilder.core import ActivityHandler, ConversationState, UserState, TurnContext
from ilens_luis import IlensLuis
from helpers.luis_helper import LuisHelper, Intent


class task_details(CancelAndHelpDialog):
    def __init__(self, luis_recognizer: IlensLuis, user_state: UserState):
        super(task_details, self).__init__(task_details.__name__)
        self.add_dialog(TextPrompt(TextPrompt.__name__))
        self.add_dialog(ConfirmPrompt(ConfirmPrompt.__name__))
        self.add_dialog(ChoicePrompt(ChoicePrompt.__name__))
        self._luis_recognizer = luis_recognizer
        self.add_dialog(
            WaterfallDialog(
                WaterfallDialog.__name__,
                [
                    # self.first_step, self.second_step, self.end_step
                    self.first_step, self.second_step, self.third_step, self.fourth_step, self.fifth_step,
                    self.sixth_step, self.seventh_step, self.eighth_step, self.end_step
                ],
            )
        )
        self.user_state = user_state
        self.user_profile_accessor = self.user_state.create_property("UserProfile")
        self.initial_dialog_id = WaterfallDialog.__name__
        self.step_val = None
        self.observations = None
        self.mechanical = None
        self.bushing = None

    async def first_step(self, step_context: WaterfallStepContext) -> DialogTurnResult:
        """
        Complete the interaction and end the dialog.
        :param step_context:
        :return DialogTurnResult:
        """
        print("Step-1")
        user_profile = await self.user_profile_accessor.get(step_context.context, UserProfile)
        if not user_profile.card:
            user_profile.card = True
            task_card = self.create_adaptive_card_attachment("../cards/task.json")
            response = MessageFactory.attachment(task_card)
            await step_context.context.send_activity(response)
        await step_context.context.send_activity("Now starting STEP 1 of 2     Safety checklist")
        reply = MessageFactory.text("Are you wearing safety Helmet?")
        reply.suggested_actions = SuggestedActions(
            actions=[
                CardAction(
                    title="Yes",
                    type=ActionTypes.im_back,
                    value='yes'
                ),
                CardAction(
                    title="No",
                    type=ActionTypes.im_back,
                    value='no'
                )
            ]
        )
        return await step_context.prompt(
            TextPrompt.__name__, PromptOptions(prompt=reply)
        )

    async def second_step(self, step_context: WaterfallStepContext) -> DialogTurnResult:
        """
        Complete the interaction and end the dialog.
        :param step_context:
        :return DialogTurnResult:
        """
        print("Step-2")
        user_profile = await self.user_profile_accessor.get(step_context.context, UserProfile)
        res, score = self.sentiment(step_context.result)
        if res is not None:
            if res == 'positive':
                user_profile.hat = True
            elif res == 'negative':
                user_profile.hat = False
            elif res == 'neutral' and score == 0.5 and step_context.result == 'no':
                user_profile.hat = False
            else:
                step_context.active_dialog.state['stepIndex'] = step_context.active_dialog.state['stepIndex'] - 2
                print(step_context.active_dialog.state['stepIndex'])
                await step_context.context.send_activity("I couldn't process whether you are wearing helmet or not ")
                return await step_context.next(step_context.result)
        reply = MessageFactory.text("Are you wearing safety Goggles?")
        reply.suggested_actions = SuggestedActions(
            actions=[
                CardAction(
                    title="Yes",
                    type=ActionTypes.im_back,
                    value='yes'
                ),
                CardAction(
                    title="No",
                    type=ActionTypes.im_back,
                    value='no'
                )
            ]
        )
        self.step_val = step_context.result
        return await step_context.prompt(
            TextPrompt.__name__, PromptOptions(prompt=reply)
        )

    async def third_step(self, step_context: WaterfallStepContext) -> DialogTurnResult:
        """
        Complete the interaction and end the dialog.
        :param step_context:
        :return DialogTurnResult:
        """
        print("Step-3")
        user_profile = await self.user_profile_accessor.get(step_context.context, UserProfile)
        res, score = self.sentiment(step_context.result)
        if res is not None:
            if res == 'positive':
                user_profile.goggles = True
            elif res == 'negative':
                user_profile.goggles = False
            elif res == 'neutral' and score == 0.5 and step_context.result == 'no':
                user_profile.goggles = False
            else:
                step_context.active_dialog.state['stepIndex'] = step_context.active_dialog.state['stepIndex'] - 2
                await step_context.context.send_activity("I couldn't process whether you are wearing goggles or not")
                return await step_context.next(self.step_val)
        reply = MessageFactory.text("Are you wearing safety Shoes?")
        reply.suggested_actions = SuggestedActions(
            actions=[
                CardAction(
                    title="Yes",
                    type=ActionTypes.im_back,
                    value='yes'
                ),
                CardAction(
                    title="No",
                    type=ActionTypes.im_back,
                    value='no'
                )
            ]
        )
        self.step_val = step_context.result
        return await step_context.prompt(
            TextPrompt.__name__, PromptOptions(prompt=reply)
        )

    async def fourth_step(self, step_context: WaterfallStepContext) -> DialogTurnResult:
        """
        Complete the interaction and end the dialog.
        :param step_context:
        :return DialogTurnResult:
        """
        print("Step-4")
        user_profile = await self.user_profile_accessor.get(step_context.context, UserProfile)
        res, score = self.sentiment(step_context.result)
        if res is not None:
            if res == 'positive':
                user_profile.shoes = True
            elif res == 'negative':
                user_profile.shoes = False
            elif res == 'neutral' and score == 0.5 and step_context.result == 'no':
                user_profile.shoes = False
            else:
                step_context.active_dialog.state['stepIndex'] = step_context.active_dialog.state['stepIndex'] - 2
                await step_context.context.send_activity("I couldn't process whether you are wearing shoes or not")
                return await step_context.next(self.step_val)
        reply = MessageFactory.text("Are you wearing safety Vest?")
        reply.suggested_actions = SuggestedActions(
            actions=[
                CardAction(
                    title="Yes",
                    type=ActionTypes.im_back,
                    value='yes'
                ),
                CardAction(
                    title="No",
                    type=ActionTypes.im_back,
                    value='no'
                )
            ]
        )
        self.step_val = step_context.result
        return await step_context.prompt(
            TextPrompt.__name__, PromptOptions(prompt=reply)
        )

    async def fifth_step(self, step_context: WaterfallStepContext) -> DialogTurnResult:
        """
        Complete the interaction and end the dialog.
        :param step_context:
        :return DialogTurnResult:
        """
        print("Step-5")
        user_profile = await self.user_profile_accessor.get(step_context.context, UserProfile)
        res, score = self.sentiment(step_context.result)
        if res is not None:
            if res == 'positive':
                user_profile.vest = True
            elif res == 'negative':
                user_profile.vest = False
            elif res == 'neutral' and score == 0.5 and step_context.result == 'no':
                user_profile.vest = False
            else:
                step_context.active_dialog.state['stepIndex'] = step_context.active_dialog.state['stepIndex'] - 2
                await step_context.context.send_activity("I couldn't process whether you are wearing vest or not")
                return await step_context.next(self.step_val)

        safety_card_path = self.load_safety_card(str(user_profile.hat).lower(), str(user_profile.goggles).lower(),
                                                 str(user_profile.shoes).lower(), str(user_profile.vest).lower())
        task_card = self.create_adaptive_card_attachment(safety_card_path)
        response = MessageFactory.attachment(task_card)
        await step_context.context.send_activity(response)

        reply = MessageFactory.text("Do you want to submit your responses?")
        reply.suggested_actions = SuggestedActions(
            actions=[
                CardAction(
                    title="Yes",
                    type=ActionTypes.im_back,
                    value='yes'
                ),
                CardAction(
                    title="No",
                    type=ActionTypes.im_back,
                    value='no'
                )
            ]
        )
        self.step_val = step_context.result
        return await step_context.prompt(
            TextPrompt.__name__, PromptOptions(prompt=reply)
        )
        # self.step_val = step_context.result
        # return await step_context.end_dialog()

    async def sixth_step(self, step_context: WaterfallStepContext) -> DialogTurnResult:
        """
        Complete the interaction and end the dialog.
        :param step_context:
        :return DialogTurnResult:
        """
        print("Step-6")
        print(self.step_val)
        user_profile = await self.user_profile_accessor.get(step_context.context, UserProfile)
        res, score = self.sentiment(step_context.result)
        if res is not None:
            if res == 'positive':
                pass
            elif res == 'negative':
                await step_context.context.send_activity("Restarting the Dialog")
                return await step_context.begin_dialog(self.id)
            elif res == 'neutral' and score == 0.5 and step_context.result == 'no':
                await step_context.context.send_activity("Let us start again")
                return await step_context.begin_dialog(self.id)
            else:
                step_context.active_dialog.state['stepIndex'] = step_context.active_dialog.state['stepIndex'] - 2
                await step_context.context.send_activity("I couldn't process whether you are willing to submit your "
                                                         "details or not")
                return await step_context.next(self.step_val)

        await step_context.context.send_activity("Now starting STEP 2 of 2     Visual Inspection")
        reply = MessageFactory.text("Observations*")

        reply.suggested_actions = SuggestedActions(
            actions=[
                CardAction(
                    title="Discoloration",
                    type=ActionTypes.im_back,
                    value='Discoloration'
                ),
                CardAction(
                    title="change in sound",
                    type=ActionTypes.im_back,
                    value='change in sound'
                ),
                CardAction(
                    title="Visible leak",
                    type=ActionTypes.im_back,
                    value='Visible leak'
                )
            ]
        )

        self.step_val = step_context.result
        return await step_context.prompt(
            TextPrompt.__name__, PromptOptions(prompt=reply)
        )

    async def seventh_step(self, step_context: WaterfallStepContext) -> DialogTurnResult:
        """
        Complete the interaction and end the dialog.
        :param step_context:
        :return DialogTurnResult:
        """
        print("Step-7")
        print(self.step_val)
        user_profile = await self.user_profile_accessor.get(step_context.context, UserProfile)
        if not self._luis_recognizer.is_configured:
            await step_context.context.send_activity("My Luis is not configured")
            return await step_context.end_dialog()
        intent, luis_result = await LuisHelper.execute_luis_query(self._luis_recognizer, step_context.context)
        print(intent)
        if intent == Intent.discoloration.value or step_context.result == "Discoloration":
            self.observations = 'discoloration'
            user_profile.discoloration = True
        elif intent == Intent.change_in_sound.value or step_context.result == "change in sound":
            self.observations = 'change_in_sound'
            user_profile.change_in_sound = True
        elif intent == Intent.leak.value or step_context.result == "Visible leak":
            user_profile.leak = True
            self.observations = 'leak'
        else:
            step_context.active_dialog.state['stepIndex'] = step_context.active_dialog.state['stepIndex'] - 2
            await step_context.context.send_activity("I couldn't process your Observations")
            return await step_context.next(self.step_val)
        reply = MessageFactory.text("Mechanical Seal for Leakage *")

        reply.suggested_actions = SuggestedActions(
            actions=[
                CardAction(
                    title="Safe",
                    type=ActionTypes.im_back,
                    value='safe'
                ),
                CardAction(
                    title="At risk",
                    type=ActionTypes.im_back,
                    value='risk'
                ),
                CardAction(
                    title="Not applicable",
                    type=ActionTypes.im_back,
                    value='not applicable'
                )
            ]
        )
        self.step_val = step_context.result
        return await step_context.prompt(
            TextPrompt.__name__, PromptOptions(prompt=reply)
        )

    async def eighth_step(self, step_context: WaterfallStepContext) -> DialogTurnResult:
        """
        Complete the interaction and end the dialog.
        :param step_context:
        :return DialogTurnResult:
        """
        print("Step-8")
        print(self.step_val)
        user_profile = await self.user_profile_accessor.get(step_context.context, UserProfile)
        if not self._luis_recognizer.is_configured:
            await step_context.context.send_activity("My Luis is not configured")
            return await step_context.end_dialog()
        intent, luis_result = await LuisHelper.execute_luis_query(self._luis_recognizer, step_context.context)
        print(intent)
        if intent == Intent.safe.value or step_context.result == 'safe':
            self.mechanical = 'safe'
            user_profile.safe = True
        elif intent == Intent.risk.value or step_context.result == 'risk':
            user_profile.risk = True
            self.mechanical = 'risk'
        elif intent == Intent.not_applicable.value or step_context.result == 'not applicable':
            user_profile.not_applicable = True
            self.mechanical = 'not_applicable'
        else:
            step_context.active_dialog.state['stepIndex'] = step_context.active_dialog.state['stepIndex'] - 2
            await step_context.context.send_activity("I couldn't process your leakage details")
            return await step_context.next(self.step_val)
        reply = MessageFactory.text("Bushing Conditions*")

        reply.suggested_actions = SuggestedActions(
            actions=[
                CardAction(
                    title="Good",
                    type=ActionTypes.im_back,
                    value='good'
                ),
                CardAction(
                    title="Fair",
                    type=ActionTypes.im_back,
                    value='fair'
                ),
                CardAction(
                    title="Poor",
                    type=ActionTypes.im_back,
                    value='poor'
                )
            ]
        )
        self.step_val = step_context.result
        return await step_context.prompt(
            TextPrompt.__name__, PromptOptions(prompt=reply)
        )

    async def end_step(self, step_context: WaterfallStepContext) -> DialogTurnResult:
        user_profile = await self.user_profile_accessor.get(step_context.context, UserProfile)
        if not self._luis_recognizer.is_configured:
            await step_context.context.send_activity("My Luis is not configured")
            return await step_context.end_dialog()
        intent, luis_result = await LuisHelper.execute_luis_query(self._luis_recognizer, step_context.context)
        print(intent)
        if intent == Intent.good.value or step_context.result == 'good':
            self.bushing = 'good'
            user_profile.good = True
        elif intent == Intent.fair.value or step_context.result == 'fair':
            self.bushing = 'fair'
            user_profile.fair = True
        elif intent == Intent.poor.value or step_context.result == 'poor':
            self.bushing = 'poor'
            user_profile.poor = True
        else:
            step_context.active_dialog.state['stepIndex'] = step_context.active_dialog.state['stepIndex'] - 2
            await step_context.context.send_activity("I couldn't process your bushing details")
            return await step_context.next(self.step_val)
        inspection_card_path = self.load_inspection_card(self.observations,self.mechanical,self.bushing)
        task_card = self.create_adaptive_card_attachment(inspection_card_path)
        response = MessageFactory.attachment(task_card)
        await step_context.context.send_activity(response)
        await step_context.context.send_activity("Thank you for completing your tasks")
        self.step_val = step_context.result
        return await step_context.end_dialog()

    def is_ambiguous(self, timex: str) -> bool:
        timex_property = Timex(timex)
        return "definite" not in timex_property.types

    def create_adaptive_card_attachment(self, path):
        relative_path = os.path.abspath(os.path.dirname(__file__))
        path = os.path.join(relative_path, path)
        with open(path) as in_file:
            card = json.load(in_file)

        return Attachment(
            content_type="application/vnd.microsoft.card.adaptive", content=card
        )

    def _to_choices(self, choices: [str]) -> List[Choice]:
        choice_list: List[Choice] = []
        for choice in choices:
            choice_list.append(Choice(value=choice))
        return choice_list

    def sentiment(self, question):
        import requests

        url = "https://westus.api.cognitive.microsoft.com/luis/prediction/v3.0/apps/45646243-2016-4f0a-9145-e93a7f58e355/slots/production/predict?subscription-key=f19be164fbfc49a3972f940835820d7e&verbose=true&show-all-intents=true&log=true&query=" + question

        payload = {}
        headers = {}

        response = requests.request("GET", url, headers=headers, data=payload)
        try:
            res = response.json()['prediction']['sentiment']['label']
            return res, response.json()['prediction']['sentiment']['score']
        except:
            return None

    def load_safety_card(self, hat, goggles, shoes, vest):
        import json
        path = "../cards/safety_check_list.json"
        relative_path = os.path.abspath(os.path.dirname(__file__))
        path = os.path.join(relative_path, path)
        f = open(path, "r")
        data = json.loads(f.read())
        for i in data['body']:
            if i['type'] == 'Container':
                for j in i['items']:
                    if j['type'] == 'Input.Toggle':
                        if hat == 'true':
                            if j['id'] == 'hat_yes':
                                j['value'] = 'true'
                            if j['id'] == 'hat_no':
                                j['value'] = 'false'
                        else:
                            if j['id'] == 'hat_no':
                                j['value'] = 'true'
                            if j['id'] == 'hat_yes':
                                j['value'] = 'false'
                        if goggles == 'true':
                            if j['id'] == 'goggles_yes':
                                j['value'] = 'true'
                            if j['id'] == 'goggles_no':
                                j['value'] = 'false'
                        else:
                            if j['id'] == 'goggles_no':
                                j['value'] = 'true'
                            if j['id'] == 'goggles_yes':
                                j['value'] = 'false'
                        if vest == 'true':
                            if j['id'] == 'vest_yes':
                                j['value'] = 'true'
                            if j['id'] == 'vest_no':
                                j['value'] = 'false'
                        else:
                            if j['id'] == 'vest_no':
                                j['value'] = 'true'
                            if j['id'] == 'vest_yes':
                                j['value'] = 'false'
                        if shoes == 'true':
                            if j['id'] == 'shoes_yes':
                                j['value'] = 'true'
                            if j['id'] == 'shoes_no':
                                j['value'] = 'false'
                        else:
                            if j['id'] == 'shoes_no':
                                j['value'] = 'true'
                            if j['id'] == 'shoes_yes':
                                j['value'] = 'false'
        out_file = open(path, "w")

        json.dump(data, out_file, indent=6)
        out_file.close()
        return "../cards/safety_check_list.json"

    def load_inspection_card(self, observations, mechanical, bushing):
        import json
        path = "../cards/inspection.json"
        relative_path = os.path.abspath(os.path.dirname(__file__))
        path = os.path.join(relative_path, path)
        f = open(path, "r")
        data = json.loads(f.read())
        for i in data['body']:
            if i['type'] == 'Container':
                for j in i['items']:
                    if j['type'] == 'Input.Toggle':
                        j['value'] = 'false'
        for i in data['body']:
            if i['type'] == 'Container':
                for j in i['items']:
                    if j['type'] == 'Input.Toggle':
                        if j['id'] == observations or j['id'] == mechanical or j['id'] == bushing:
                            j['value'] = 'true'

        out_file = open(path, "w")

        json.dump(data, out_file, indent=6)
        out_file.close()
        return "../cards/inspection.json"
