// SPDX-FileCopyrightText: 2023 g10 code GmbH
// SPDX-Contributor: Carl Schwan <carl.schwan@gnupg.com>
// SPDX-License-Identifier: GPL-2.0-or-later

/**
 * Download the mail content from the EWS API
 * @returns {Promise<string>}
 */
function downloadViaRest(item) {
  return new Promise((resolve, reject) => {
    const request =
      '<?xml version="1.0" encoding="utf-8"?>' +
      '<soap:Envelope xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"' +
      '               xmlns:xsd="https://www.w3.org/2001/XMLSchema"' +
      '               xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"' +
      '               xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">' +
      '  <soap:Header>' +
      '    <RequestServerVersion Version="Exchange2013" xmlns="http://schemas.microsoft.com/exchange/services/2006/types" soap:mustUnderstand="0" />' +
      '  </soap:Header>' +
      '  <soap:Body>' +
      '    <GetItem xmlns="http://schemas.microsoft.com/exchange/services/2006/messages">' +
      '      <ItemShape>' +
      '        <t:BaseShape>IdOnly</t:BaseShape>' +
      '        <t:IncludeMimeContent>true</t:IncludeMimeContent>' +
      '      </ItemShape>' +
      '      <ItemIds><t:ItemId Id="' + item.itemId + '"/></ItemIds>' +
      '    </GetItem>' +
      '  </soap:Body>' +
      '</soap:Envelope>';

    Office.context.mailbox.makeEwsRequestAsync(request, (asyncResult) => {
      const parser = new DOMParser();
      xmlDoc = parser.parseFromString(asyncResult.value, "text/xml");

      const mimeContent = xmlDoc.getElementsByTagName('t:MimeContent')[0].innerHTML;
      resolve(atob(mimeContent));
    });
  })
}

const {createApp} = Vue

function i18n(text) {
  const lang = Office.context.displayLanguage
  if (lang in messages && text in messages[lang]) {
    return messages[lang][text];
  }
  return text;
}

function i18nc(context, text) {
  const lang = Office.context.displayLanguage
  console.log(lang)
  if (lang in messages && text in messages[lang]) {
    return messages[lang][text];
  }
  return text;
}

const vueApp = {
  data() {
    return {
      error: '',
      content: '',
      hasSelection: true,
      status: {
        encrypted: false,
        signed: false,
        drafts: [],
      },
      socket: null,
    }
  },
  computed: {
    loaded() {
      return this.content.length > 0;
    },
    statusText() {
      if (!this.loaded) {
        return i18nc("Loading placeholder", "Loading...");
      }
      if (this.status.encrypted) {
        return this.status.signed ? i18n("This mail is encrypted and signed.") : i18n("This mail is encrypted.");
      }
      if (this.status.signed) {
        return i18n("This mail is signed")
      }
      return i18n("This mail is not encrypted nor signed.");
    },
    decryptButtonText() {
      if (!this.loaded) {
        return '';
      }
      if (this.status.encrypted) {
        return this.i18nc("@action:button", "Decrypt")
      }

      return this.i18nc("@action:button", "View email")
    }
  },
  methods: {
    i18n,
    i18nc,
    async view() {
      const response = await fetch('/view', {
        method: 'POST',
        body: this.content,
        headers: {
          'X-EMAIL': Office.context.mailbox.userProfile.emailAddress,
          'X-NAME': Office.context.mailbox.userProfile.displayName,
        },
      });
    },

    async reply() {
      await fetch('/reply', {
        method: 'POST',
        body: this.content,
        headers: {
          'X-EMAIL': Office.context.mailbox.userProfile.emailAddress,
          'X-NAME': Office.context.mailbox.userProfile.displayName,
        },
      });
    },
    async forward() {
      await fetch('/forward', {
        method: 'POST',
        body: this.content,
        headers: {
          'X-EMAIL': Office.context.mailbox.userProfile.emailAddress,
          'X-NAME': Office.context.mailbox.userProfile.displayName,
        },
      });
    },
    async newEmail() {
      const response = await fetch('/new', {
        method: 'POST',
        headers: {
          'X-EMAIL': Office.context.mailbox.userProfile.emailAddress,
          'X-NAME': Office.context.mailbox.userProfile.displayName,
        },
      });
    },
    async openDraft(id) {
      const response = await fetch(`/draft/${id}`, {
        method: 'POST',
        headers: {
          'X-EMAIL': Office.context.mailbox.userProfile.emailAddress,
          'X-NAME': Office.context.mailbox.userProfile.displayName,
        },
      });
    },
    async deleteDraft(id) {
      const response = await fetch(`/draft/${id}`, {
        method: 'DELETE',
        headers: {
          'X-EMAIL': Office.context.mailbox.userProfile.emailAddress,
          'X-NAME': Office.context.mailbox.userProfile.displayName,
        },
      });
    },
    async info() {
      const response = await fetch('/info', {
        method: 'POST',
        body: this.content,
        headers: {
          'X-EMAIL': Office.context.mailbox.userProfile.emailAddress,
          'X-NAME': Office.context.mailbox.userProfile.displayName,
        },
      });
      const status = await response.json();
      this.status.encrypted = status.encrypted;
      this.status.signed = status.signed;
      this.status.drafts = status.drafts;
    },
    displayDate(timestamp) {
      const date = new Date(timestamp * 1000);
      let todayDate = new Date();
      let lastModification = '';
      if ((new Date(date)).setHours(0, 0, 0, 0) === todayDate.setHours(0, 0, 0, 0)) {
        return date.toLocaleTimeString([], {
          hour: 'numeric',
          minute: 'numeric',
        });
      } else {
        return date.toLocaleDateString();
      }
    },
    async downloadContent() {
      this.content = await downloadViaRest(Office.context.mailbox.item);
      this.hasSelection = true;
      await this.info()
    }
  },
  async mounted() {
    await this.downloadContent();

    Office.context.mailbox.addHandlerAsync(Office.EventType.ItemChanged, (eventArgs) => {
        if (Office.context.mailbox.item) {
            this.downloadContent();
        } else {
            this.content = '';
            this.hasSelection = false;
        }
    });

    function webSocketConnect() {
      this.socket = new WebSocket("wss://localhost:5657");

      // Connection opened
      this.socket.addEventListener("open", (event) => {
        this.error = '';
        this.socket.send(JSON.stringify({
          command: "register",
          arguments: {
            emails: [Office.context.mailbox.userProfile.emailAddress],
            type: 'webclient',
          },
        }));
      });

      this.socket.addEventListener("close", (event) => {
        this.error = i18n("Native client was disconnected");
        setTimeout(function () {
          webSocketConnect();
        }, 1000);
      });

      this.socket.addEventListener("error", (event) => {
        this.error = i18n("Native client received an error");
        setTimeout(function () {
          webSocketConnect();
        }, 1000);
      });

      // Listen for messages
      this.socket.addEventListener("message", ({data}) => {
        const message = JSON.parse(data);
        console.log("Message from server ", message);
        switch (message.type) {
          case 'ews':
            Office.context.mailbox.makeEwsRequestAsync(message.payload, (asyncResult) => {
              console.log('Email sent')
              // let the client known that the email was sent
              this.socket.send(JSON.stringify({
                command: 'email-sent',
                arguments: {
                  id: message.id,
                  email: Office.context.mailbox.userProfile.emailAddress,
                }
              }));
            });
            break;
          case 'disconnection':
            this.error = i18n("Native client was disconnected")
            break;
          case 'connection':
            this.error = '';
            break;
        }
      });
    }

    webSocketConnect();
  },
}

Office.onReady().then(() => {
  createApp(vueApp).mount('#app')
  document.getElementById('app').classList.remove('d-none');
});
