<template>
  <div
    v-show="!isHidden"
    class="webChat__Container kettalComponent"
    :active="isClosed"
  >
    <div class="webChat__header">
      <div class="webChat__title">
        {{ title }}
      </div>
      <img
        class="webChat__closeButton"
        src="~assets/icons/ExitKettal.svg"
        @click="closeWebChat"
      >
    </div>
    <div
      id="webchat"
      role="main"
      class="webchat"
    />
    <div
      class="webChat__icon"
      @click="openWebChat"
    >
      <i class="fa-solid fa-headset" />
    </div>
    <div
      v-if="showHiddeWebchatButton"
      class="webChat__removeWebChat"
      @click="setWebChatHiddenTo(true)"
    >
      <img src="~assets/icons/ExitKettal.svg">
    </div>
  </div>
</template>
<script setup>
import axios from 'axios'
import { debounce, useQuasar } from 'quasar'
import { defineModel, onMounted, ref } from 'vue'

const $q = useQuasar()
const conversationId = ref(
  $q.cookies.get('conversationId') === undefined ||
    $q.cookies.get('conversationId') === null
    ? ''
    : $q.cookies.get('conversationId')
)
const activities = ref([])

const props = defineProps({
  /** Initials of the user to be shown in the webchat */
  userInitials: {
    type: String,
    default: 'U'
  },
  /** Array of commands to be shown in the webchat
     * structure: {
          commandName: '',
          displayCommandIf: ['',''], This list contains the words that will trigger the command to appear
          label: '',
          function: ''}
     *
    */
  commands: {
    type: Object,
    default: () => {}
  },
  /** Boolean that indicates if the webchat should be hidden */
  showHiddeWebchatButton: {
    type: Boolean,
    default: true
  },
  /** Domain of cookies */
  cookiesDomain: {
    type: String,
    default: ''
  },
  /** Title of chat bot */
  title: {
    type: String,
    default: 'Kettal WebChat'
  },
  /**
     * The user object should have the following structure:
     * {
          dynamicsUserId: '',
          name: '',
          email: '',
          languageId: '',
          accessToken: ''
        }
     *
     */
  user: {
    type: Object,
    default: () => {
      return {
        dynamicsUserId: '',
        name: '',
        email: '',
        languageId: '',
        accessToken: ''
      }
    }
  }
})
const isClosed = defineModel('isClosed', { required: true, type: Boolean })
const isHidden = defineModel('isHidden', { required: true, type: Boolean })

onMounted(() => {
  if ($q.cookies.get('isClosed') === undefined) {
    $q.cookies.set('isClosed', false, {
      domain: props.cookiesDomain,
      expires: 365
    })
  } else {
    isClosed.value = $q.cookies.get('isClosed')
  }
  if ($q.cookies.get('webChatHidden') === undefined) {
    $q.cookies.set('webChatHidden', false, {
      domain: props.cookiesDomain,
      expires: 365
    })
  } else {
    isHidden.value = $q.cookies.get('webChatHidden') === 'true'
  }
  const webChatScript = document.createElement('script')
  webChatScript.setAttribute(
    'src',
    'https://cdn.botframework.com/botframework-webchat/latest/webchat.js'
  )
  document.head.appendChild(webChatScript)
  if (
    $q.cookies.get('accessToken') !== undefined &&
    $q.cookies.get('accessToken') !== null &&
    $q.cookies.get('accessToken') !== ''
  ) {
    //   Set style options.
    const styleOptions = {
      botAvatarInitials: 'K',
      userAvatarInitials: props.userInitials.toUpperCase()
    }

    const token = 'q8G0WtCgeVg.X9vxACJzFHp3623w81lsL0NlFbwh3uvQMyXs6OKJsaI'

    // ======================================

    webChatScript.onload = async () => {
      if (conversationId.value === '') {
        createConversation(token)
      }
      const d1 = window.WebChat.createDirectLine({
        token,
        conversationId: conversationId.value
      })
      await getWebchatHistory(token)
      const store = window.WebChat.createStore(
        {
          activities: activities.value
        },
        ({ dispatch }) =>
          (next) =>
            async (action) => {
              if (action.type === 'DIRECT_LINE/CONNECT_FULFILLED') {
                if (
                  activities.value.length === 0 ||
                  activities.value[activities.value.length - 1].attachments
                    .length === 0
                ) {
                  dispatch({
                    type: 'WEB_CHAT/SEND_EVENT',
                    payload: {
                      name: 'webchat/join'
                    }
                  })
                }
              } else if (action.type === 'DIRECT_LINE/INCOMING_ACTIVITY') {
                console.log(action)
                if (!action.payload.activity.attachments) {
                  setWebChatHiddenTo(false)
                  openWebChat()
                }
                $q.cookies.set(
                  'lastWatermark',
                  action.payload.activity.id.split('|')[1],
                  {
                    domain: props.cookiesDomain,
                    expires: 365
                  }
                )
              }
              return next(action)
            }
      )
      await window.WebChat.renderWebChat(
        {
          directLine: Object.assign({}, d1, {
            postActivity: (activity) => {
              const newActivity = Object.assign({}, activity)
              newActivity.from = {
                id: props.user.dynamicsUserId,
                name: props.user.name,
                token: props.user.accessToken,
                email: props.user.email,
                locale: props.user.languageId
              }
              return d1.postActivity(newActivity)
            }
          }),
          store,
          userID: props.user.dynamicsUserId,
          username: props.user.name,
          locale: props.user.languageId,
          styleOptions
        },
        document.getElementById('webchat')
      )

      addHTMLToWebChat(store)
    }
  }
})

async function createConversation (botToken) {
  await axios
    .post(
      'https://directline.botframework.com/v3/directline/conversations',
      {},
      {
        headers: {
          Authorization: 'Bearer ' + botToken
        }
      }
    )
    .then((response) => {
      conversationId.value = response.data.conversationId
      $q.cookies.set('conversationId', conversationId.value, {
        domain: props.cookiesDomain,
        expires: 365
      })
    })
}

async function getWebchatHistory (botToken) {
  // ======================================
  // https://github.com/microsoft/BotFramework-WebChat/issues/4973
  // ======================================
  await axios(
    'https://directline.botframework.com/v3/directline/conversations/' +
      conversationId.value +
      '/activities?watermark=',
    { headers: { Authorization: 'Bearer ' + botToken } }
  ).then((response) => {
    for (
      let i = response.data.activities.length - 1;
      activities.value.length < 100 && i > 0;
      i--
    ) {
      if (response.data.activities[i].type === 'message') {
        /**
         * The channelData property is required. Additionally, it cannot be an empty object ({}).
         * Excluding channelData or passing in an empty object will generate the Cannot read properties of undefined (reading 'has') error.
         */
        /**
         * channelData (or, rather, Web Chat) requires the webchat:fallback-text property to be present.
         * It takes a string value which can be empty.
         */
        if (!Object.keys(response.data.activities[i]).includes('channelData')) {
          response.data.activities[i].channelData = {
            'webchat:fallback-text': ''
          }
        } else {
          /**
           * If there is a clientActivityID property present in channelData, remove this. Web Chat, thru its own mechanisms,
           * attempts to use some part of this property's value to generate the key assigned to the underlying React element.
           * If the value is the same across multiple activities, it will render each activity in the transcript window,
           * but it will also generate a React error in the developer's console. And, as these activities are historical and only being fed thru,
           *  their removal should have no impact in Web Chat.
           */
          response.data.activities[i].channelData.clientActivityID = ''
        }
        if (
          response.data.activities[i].from !== undefined &&
          response.data.activities[i].from.id === props.user.dynamicsUserId
        ) {
          response.data.activities[i].from.role = 'user'
        }
        response.data.activities[i].localTimestamp = ''
        activities.value.unshift(response.data.activities[i])
      }
    }
    if (activities.value.length === 0) return
    const lastMessageWatermark =
      activities.value[activities.value.length - 1].id.split('|')[1]
    if (
      parseInt($q.cookies.get('lastWatermark')) !==
      parseInt(lastMessageWatermark)
    ) {
      setWebChatHiddenTo(false)
      openWebChat()
      isClosed.value = 'true'
      $q.cookies.set('lastWatermark', parseInt(lastMessageWatermark), {
        domain: props.cookiesDomain,
        expires: 365
      })
    }
  })
}
function addHTMLToWebChat (store) {
  const scrollableElement = document.getElementsByClassName(
    'webchat__basic-transcript__scrollable'
  )[0]
  scrollableElement.addEventListener('scroll', () => {
    checkIfIsOnTop(store)
  })

  const commandsContainer = document.createElement('div')

  const bottomChatBar = document.getElementsByClassName('webchat__send-box')[0]
  const bottomChatBarMain = document.getElementsByClassName(
    'webchat__send-box__main'
  )[0]
  bottomChatBar.insertBefore(commandsContainer, bottomChatBarMain)

  const input = document.getElementsByClassName(
    'webchat__send-box-text-box__input'
  )[0]
  function showCommands () {
    commandsContainer.innerHTML = ''
    if (input.value === '') return
    props.commands
      .filter((command) => {
        let isCommand = false
        command.displayCommandIf.forEach((string) => {
          if (
            string.toLocaleLowerCase().includes(input.value.toLocaleLowerCase())
          ) {
            isCommand = true
          }
        })
        return isCommand
      })
      .forEach((command) => {
        const commandButton = document.createElement('div')
        commandButton.className = 'command__button'
        commandButton.innerHTML = command.label
        commandButton.addEventListener('click', () => {
          input.value = ''
          input.value = command.function
          input.setAttribute('value', '')
          const action = {
            type: 'WEB_CHAT/SET_SEND_BOX',
            payload: {
              text: command.function
            }
          }
          store.dispatch(action)
          commandsContainer.innerHTML = ''
        })
        commandsContainer.appendChild(commandButton)
      })
  }
  input.addEventListener('input', function () {
    debounce(showCommands, 500)()
  })
}
function checkIfIsOnTop () {
  const scrollableElement = document.getElementsByClassName(
    'webchat__basic-transcript__scrollable'
  )[0]
  if (scrollableElement.scrollTop <= 0) {
    console.log('Scroll position is at the top')
  }
}
function openWebChat () {
  $q.cookies.set('isClosed', true, {
    domain: props.cookiesDomain,
    expires: 365
  })
  isClosed.value = 'true'
}

function closeWebChat () {
  $q.cookies.set('isClosed', false, {
    domain: props.cookiesDomain,
    expires: 365
  })
  isClosed.value = 'false'
}
function setWebChatHiddenTo (isVisible) {
  $q.cookies.set('webChatHidden', isVisible, {
    domain: props.cookiesDomain,
    expires: 365
  })
  isHidden.value = isVisible
  $q.cookies.set('isClosed', isVisible, {
    domain: props.cookiesDomain,
    expires: 365
  })
  isClosed.value = isVisible
}
</script>
<style lang="scss">
.kettalComponent{
.webChat__Container {
  position: absolute;
  bottom: 0;
  right: 0;
  margin: 3.5rem 2rem;
  z-index: 10000;
  background-color: white;
  border: 1px solid black;
  display: flex;
  flex-direction: column;
  transition: all 0.2s ease-in-out;
}
.webChat__Container[active="true"] {
  height: min(40rem, 90vh);
  width: min(400px, 80vw);
  overflow: hidden;
}

.webChat__Container[active="false"] .webChat__header,
.webChat__Container[active="false"] .webchat {
  display: none;
  transition: all 1s ease-in-out;
}

.webChat__Container[active="false"] {
  height: 60px;
  width: 60px;
  border-radius: 60px;
  cursor: pointer;
}
.webChat__Container[active="false"] .webChat__icon {
  height: 100%;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  align-content: center;
}
.webChat__removeWebChat {
  display: none;
}
.webChat__Container[active="false"]:hover .webChat__removeWebChat {
  position: absolute;
  top: -5px;
  right: -5px;
  z-index: 100001;
  border: 1px solid black;
  height: 20px;
  width: 20px;
  display: block;
  border-radius: 30px;
  overflow: hidden;
  background-color: white;
}
.webChat__removeWebChat > img {
  height: 100%;
  width: 100%;
}
.webChat__Container[active="false"] .webChat__icon i {
  font-size: 2rem;
}
.webChat__Container[active="true"] .webChat__icon {
  display: none;
}

.webchat {
  height: 35rem;
  flex: 1;
}

.webChat__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-inline: 1rem;
  padding-bottom: 1rem;
  height: 4rem;
  width: 100%;
  border-radius: 10px 10px 0 0;
  font-size: 24px;
  align-items: center;
  align-content: center;
}

.webChat__closeButton {
  display: flex;
  align-items: center;
  justify-content: center;
  top: 0px;
  right: 0px;
  height: 1.5rem;
  width: 1.5rem;
  cursor: pointer;
}

.webChat__Container[hidden="true"] {
  display: none;
}
.command__button {
  display: flex;
  align-items: center;
  justify-content: center;
  padding-block: 0.5rem;
  cursor: pointer;
  border-top: 1px solid rgb(230, 230, 230);
}

.command__button:hover {
  background-color: rgb(230, 230, 230);
}
}
</style>
