<template>
  <div>
    <div class="mb-6 flex flex-col md:flex-row justify-between md:items-center">
      <div class="relative">
        <input
          v-model="search"
          @keyup.esc="search = ''"
          tabindex="0"
          type="text"
          class="w-full md:w-64 appearance-none shadow bg-white text-grey-700 focus:outline-none rounded py-3 pl-3 pr-8"
          placeholder="Search Recipients"
        />
        <icon
          v-if="search"
          @click.native="search = ''"
          name="close-circle"
          class="absolute right-0 inset-y-0 w-5 h-full text-grey-300 fill-current mr-2 flex items-center cursor-pointer"
        />
        <icon
          v-else
          name="search"
          class="absolute right-0 inset-y-0 w-5 h-full text-grey-300 fill-current pointer-events-none mr-2 flex items-center"
        />
      </div>
      <div class="mt-4 md:mt-0">
        <button
          @click="addRecipientModalOpen = true"
          class="bg-cyan-400 hover:bg-cyan-300 text-cyan-900 font-bold py-3 px-4 rounded focus:outline-none ml-auto"
        >
          Add Recipient
        </button>
      </div>
    </div>

    <vue-good-table
      @on-search="debounceToolips"
      :columns="columns"
      :rows="rows"
      :search-options="{
        enabled: true,
        skipDiacritics: true,
        externalQuery: search,
      }"
      :sort-options="{
        enabled: true,
        initialSortBy: { field: 'created_at', type: 'desc' },
      }"
      styleClass="vgt-table"
    >
      <div slot="emptystate" class="flex items-center justify-center h-24 text-lg text-grey-700">
        No recipients found for that search!
      </div>
      <template slot="table-column" slot-scope="props">
        <span v-if="props.column.label == 'Key'">
          Key
          <span
            class="tooltip outline-none"
            :data-tippy-content="
              `Use this to attach recipients to new aliases as they are created e.g. alias+key@${
                user.username
              }.anonaddy.com. You can attach multiple recipients by doing alias+2.3.4@${
                user.username
              }.anonaddy.com. Separating each key by a full stop.`
            "
          >
            <icon name="info" class="inline-block w-4 h-4 text-grey-200 fill-current" />
          </span>
        </span>
        <span v-else>
          {{ props.column.label }}
        </span>
      </template>
      <template slot="table-row" slot-scope="props">
        <span
          v-if="props.column.field == 'created_at'"
          class="tooltip outline-none text-sm"
          :data-tippy-content="rows[props.row.originalIndex].created_at | formatDate"
          >{{ props.row.created_at | timeAgo }}
        </span>
        <span v-else-if="props.column.field == 'key'">
          {{ props.row.key }}
        </span>
        <span v-else-if="props.column.field == 'email'">
          <span
            class="tooltip cursor-pointer outline-none"
            data-tippy-content="Click to copy"
            v-clipboard="() => rows[props.row.originalIndex].email"
            v-clipboard:success="clipboardSuccess"
            v-clipboard:error="clipboardError"
            >{{ props.row.email | truncate(30) }}</span
          >

          <span
            v-if="isDefault(props.row.id)"
            class="ml-3 py-1 px-2 text-sm bg-yellow-200 text-yellow-900 rounded-full tooltip"
            data-tippy-content="The default recipient will be used for all aliases with no other recipients assigned"
          >
            default
          </span>
        </span>
        <span v-else-if="props.column.field === 'aliases'">
          <span
            v-if="props.row.aliases.length"
            class="tooltip outline-none"
            :data-tippy-content="aliasesTooltip(props.row.aliases, isDefault(props.row.id))"
            >{{ props.row.aliases[0].email | truncate(40) }}
            <span
              v-if="isDefault(props.row.id) && aliasesUsingDefaultCount > 1"
              class="block text-grey-500 text-sm"
            >
              + {{ aliasesUsingDefaultCount - 1 }}</span
            >
            <span v-else-if="props.row.aliases.length > 1" class="block text-grey-500 text-sm">
              + {{ props.row.aliases.length - 1 }}</span
            >
          </span>
          <span v-else class="block text-grey-500 text-sm">{{ props.row.aliases.length }}</span>
        </span>
        <span v-else-if="props.column.field === 'should_encrypt'">
          <span v-if="props.row.fingerprint" class="flex">
            <Toggle
              v-model="rows[props.row.originalIndex].should_encrypt"
              @on="turnOnEncryption(props.row.id)"
              @off="turnOffEncryption(props.row.id)"
            />
            <icon
              name="fingerprint"
              class="tooltip outline-none cursor-pointer block w-6 h-6 text-grey-200 fill-current mx-2"
              :data-tippy-content="props.row.fingerprint"
              v-clipboard="() => props.row.fingerprint"
              v-clipboard:success="clipboardSuccess"
              v-clipboard:error="clipboardError"
            />
            <icon
              name="delete"
              class="tooltip outline-none cursor-pointer block w-6 h-6 text-grey-200 fill-current"
              @click.native="openDeleteRecipientKeyModal(props.row)"
              data-tippy-content="Remove public key"
            />
          </span>
          <button
            v-else
            @click="openRecipientKeyModal(props.row)"
            class="focus:outline-none text-sm"
          >
            Add public key
          </button>
        </span>
        <span v-else-if="props.column.field === 'email_verified_at'">
          <span
            name="check"
            v-if="props.row.email_verified_at"
            class="py-1 px-2 bg-green-200 text-green-900 rounded-full text-xs"
          >
            verified
          </span>
          <button
            v-else
            @click="resendVerification(props.row.id)"
            class="focus:outline-none text-sm"
            :class="resendVerificationLoading ? 'cursor-not-allowed' : ''"
            :disabled="resendVerificationLoading"
          >
            Resend email
          </button>
        </span>
        <span v-else class="flex items-center justify-center outline-none" tabindex="-1">
          <icon
            v-if="!isDefault(props.row.id)"
            name="trash"
            class="block w-6 h-6 text-grey-200 fill-current cursor-pointer"
            @click.native="openDeleteModal(props.row)"
          />
        </span>
      </template>
    </vue-good-table>

    <Modal :open="addRecipientModalOpen" @close="addRecipientModalOpen = false">
      <div class="max-w-lg w-full bg-white rounded-lg shadow-2xl p-6">
        <h2
          class="font-semibold text-grey-900 text-2xl leading-tight border-b-2 border-grey-100 pb-4"
        >
          Add new recipient
        </h2>
        <p class="mt-4 text-grey-700">
          Enter the individual email of the new recipient you'd like to add.
        </p>
        <p class="mt-4 text-grey-700">
          You will receive an email with a verification link that will expire in one hour, you can
          click "Resend email" to get a new one.
        </p>
        <div class="mt-6">
          <p v-show="errors.newRecipient" class="mb-3 text-red-500 text-sm">
            {{ errors.newRecipient }}
          </p>
          <input
            v-model="newRecipient"
            type="email"
            class="w-full appearance-none bg-grey-100 border border-transparent text-grey-700 focus:outline-none rounded p-3 mb-6"
            :class="errors.newRecipient ? 'border-red-500' : ''"
            placeholder="johndoe@example.com"
            autofocus
          />
          <button
            @click="validateNewRecipient"
            class="bg-cyan-400 hover:bg-cyan-300 text-cyan-900 font-bold py-3 px-4 rounded focus:outline-none"
            :class="addRecipientLoading ? 'cursor-not-allowed' : ''"
            :disabled="addRecipientLoading"
          >
            Add Recipient
            <loader v-if="addRecipientLoading" />
          </button>
          <button
            @click="addRecipientModalOpen = false"
            class="ml-4 px-4 py-3 text-grey-800 font-semibold bg-white hover:bg-grey-50 border border-grey-100 rounded focus:outline-none"
          >
            Cancel
          </button>
        </div>
      </div>
    </Modal>

    <Modal :open="addRecipientKeyModalOpen" @close="closeRecipientKeyModal">
      <div class="max-w-lg w-full bg-white rounded-lg shadow-2xl p-6">
        <h2
          class="font-semibold text-grey-900 text-2xl leading-tight border-b-2 border-grey-100 pb-4"
        >
          Add Public GPG Key
        </h2>
        <p class="mt-4 text-grey-700">Enter your <b>PUBLIC</b> key data in the text area below.</p>
        <p class="mt-4 text-grey-700">Make sure to remove <b>Comment:</b> and <b>Version:</b></p>
        <div class="mt-6">
          <p v-show="errors.recipientKey" class="mb-3 text-red-500 text-sm">
            {{ errors.recipientKey }}
          </p>
          <textarea
            v-model="recipientKey"
            class="w-full appearance-none bg-grey-100 border border-transparent text-grey-700 focus:outline-none rounded p-3 mb-6"
            :class="errors.recipientKey ? 'border-red-500' : ''"
            placeholder="Begins with '-----BEGIN PGP PUBLIC KEY BLOCK-----'"
            rows="10"
            autofocus
          >
          </textarea>
          <button
            type="button"
            @click="validateRecipientKey"
            class="bg-cyan-400 hover:bg-cyan-300 text-cyan-900 font-bold py-3 px-4 rounded focus:outline-none"
            :class="addRecipientKeyLoading ? 'cursor-not-allowed' : ''"
            :disabled="addRecipientKeyLoading"
          >
            Add Key
            <loader v-if="addRecipientKeyLoading" />
          </button>
          <button
            @click="closeRecipientKeyModal"
            class="ml-4 px-4 py-3 text-grey-800 font-semibold bg-white hover:bg-grey-50 border border-grey-100 rounded focus:outline-none"
          >
            Cancel
          </button>
        </div>
      </div>
    </Modal>

    <Modal :open="deleteRecipientKeyModalOpen" @close="closeDeleteRecipientKeyModal">
      <div class="max-w-lg w-full bg-white rounded-lg shadow-2xl p-6">
        <h2
          class="font-semibold text-grey-900 text-2xl leading-tight border-b-2 border-grey-100 pb-4"
        >
          Remove recipient public key
        </h2>
        <p class="mt-4 text-grey-700">
          Are you sure you want to remove the public key for this recipient? It will also be removed
          from any other recipients using the same key.
        </p>
        <div class="mt-6">
          <button
            type="button"
            @click="deleteRecipientKey(recipientKeyToDelete)"
            class="px-4 py-3 text-white font-semibold bg-red-500 hover:bg-red-600 border border-transparent rounded focus:outline-none"
            :class="deleteRecipientKeyLoading ? 'cursor-not-allowed' : ''"
            :disabled="deleteRecipientKeyLoading"
          >
            Remove public key
            <loader v-if="deleteRecipientLoading" />
          </button>
          <button
            @click="closeDeleteRecipientKeyModal"
            class="ml-4 px-4 py-3 text-grey-800 font-semibold bg-white hover:bg-grey-50 border border-grey-100 rounded focus:outline-none"
          >
            Cancel
          </button>
        </div>
      </div>
    </Modal>

    <Modal :open="deleteRecipientModalOpen" @close="closeDeleteModal">
      <div class="max-w-lg w-full bg-white rounded-lg shadow-2xl p-6">
        <h2
          class="font-semibold text-grey-900 text-2xl leading-tight border-b-2 border-grey-100 pb-4"
        >
          Delete recipient
        </h2>
        <p class="mt-4 text-grey-700">Are you sure you want to delete this recipient?</p>
        <div class="mt-6">
          <button
            type="button"
            @click="deleteRecipient(recipientToDelete)"
            class="px-4 py-3 text-white font-semibold bg-red-500 hover:bg-red-600 border border-transparent rounded focus:outline-none"
            :class="deleteRecipientLoading ? 'cursor-not-allowed' : ''"
            :disabled="deleteRecipientLoading"
          >
            Delete recipient
            <loader v-if="deleteRecipientLoading" />
          </button>
          <button
            @click="closeDeleteModal"
            class="ml-4 px-4 py-3 text-grey-800 font-semibold bg-white hover:bg-grey-50 border border-grey-100 rounded focus:outline-none"
          >
            Cancel
          </button>
        </div>
      </div>
    </Modal>
  </div>
</template>

<script>
import Modal from './../components/Modal.vue'
import Toggle from './../components/Toggle.vue'
import tippy from 'tippy.js'

export default {
  props: {
    user: {
      type: Object,
      required: true,
    },
    initialRecipients: {
      type: Array,
      required: true,
    },
    aliasesUsingDefault: {
      type: Array,
      required: true,
    },
    aliasesUsingDefaultCount: {
      type: Number,
      required: true,
    },
    domain: {
      type: String,
      required: true,
    },
  },
  components: {
    Modal,
    Toggle,
  },
  created() {
    this.defaultRecipient = _.find(this.rows, ['id', this.user.default_recipient_id])
    this.defaultRecipient.aliases = this.defaultRecipient.aliases.concat(this.aliasesUsingDefault)
  },
  mounted() {
    this.addTooltips()
  },
  data() {
    return {
      defaultRecipient: {},
      newRecipient: '',
      recipientKey: '',
      search: '',
      addRecipientLoading: false,
      addRecipientModalOpen: false,
      recipientToDelete: null,
      recipientKeyToDelete: null,
      deleteRecipientLoading: false,
      deleteRecipientModalOpen: false,
      deleteRecipientKeyLoading: false,
      deleteRecipientKeyModalOpen: false,
      addRecipientKeyLoading: false,
      addRecipientKeyModalOpen: false,
      recipientToAddKey: {},
      resendVerificationLoading: false,
      errors: {},
      columns: [
        {
          label: 'Created',
          field: 'created_at',
          globalSearchDisabled: true,
        },
        {
          label: 'Key',
          field: 'key',
          type: 'number',
        },
        {
          label: 'Email',
          field: 'email',
        },
        {
          label: 'Recipient Aliases',
          field: 'aliases',
          sortable: true,
          sortFn: this.sortRecipientAliases,
          globalSearchDisabled: true,
        },
        {
          label: 'Encryption',
          field: 'should_encrypt',
          type: 'boolean',
          globalSearchDisabled: true,
        },
        {
          label: 'Verified',
          field: 'email_verified_at',
          globalSearchDisabled: true,
        },
        {
          label: '',
          field: 'actions',
          sortable: false,
          globalSearchDisabled: true,
        },
      ],
      rows: this.initialRecipients,
    }
  },
  watch: {
    addRecipientKeyModalOpen: _.debounce(function() {
      this.addTooltips()
    }, 50),
  },
  methods: {
    addTooltips() {
      tippy('.tooltip', {
        arrow: true,
        arrowType: 'round',
      })
    },
    debounceToolips: _.debounce(function() {
      this.addTooltips()
    }, 50),
    aliasesTooltip(aliases, isDefault) {
      let ellipses =
        aliases.length > 5 || (isDefault && this.aliasesUsingDefaultCount > 5) ? '...' : ''

      return (
        _.reduce(_.take(aliases, 5), (list, alias) => list + `${alias.email}<br>`, '') + ellipses
      )
    },
    isDefault(id) {
      return this.user.default_recipient_id === id
    },
    validateNewRecipient(e) {
      this.errors = {}

      if (!this.newRecipient) {
        this.errors.newRecipient = 'Email required'
      } else if (!this.validEmail(this.newRecipient)) {
        this.errors.newRecipient = 'Valid Email required'
      }

      if (!this.errors.newRecipient) {
        this.addNewRecipient()
      }

      e.preventDefault()
    },
    addNewRecipient() {
      this.addRecipientLoading = true

      axios
        .post(
          '/api/v1/recipients',
          JSON.stringify({
            email: this.newRecipient,
          }),
          {
            headers: { 'Content-Type': 'application/json' },
          }
        )
        .then(({ data }) => {
          this.addRecipientLoading = false
          data.data.key = this.rows.length + 1
          this.rows.push(data.data)
          this.newRecipient = ''
          this.addRecipientModalOpen = false
          this.success('Recipient created and verification email sent')
        })
        .catch(error => {
          this.addRecipientLoading = false
          if (error.response.status === 422) {
            this.error(error.response.data.errors.email[0])
          } else {
            this.error()
          }
        })
    },
    resendVerification(id) {
      this.resendVerificationLoading = true

      axios
        .post(
          '/recipients/email/resend',
          JSON.stringify({
            recipient_id: id,
          }),
          {
            headers: { 'Content-Type': 'application/json' },
          }
        )
        .then(({ data }) => {
          this.resendVerificationLoading = false
          this.success('Verification email resent')
        })
        .catch(error => {
          this.resendVerificationLoading = false
          if (error.response.status === 429) {
            this.error('You can only resend the email once per minute')
          } else {
            this.error()
          }
        })
    },
    openDeleteModal(recipient) {
      this.deleteRecipientModalOpen = true
      this.recipientToDelete = recipient
    },
    closeDeleteModal() {
      this.deleteRecipientModalOpen = false
      this.recipientToDelete = null
    },
    deleteRecipient(recipient) {
      this.deleteRecipientLoading = true

      axios
        .delete(`/api/v1/recipients/${recipient.id}`)
        .then(response => {
          let recipients = _.filter(this.rows, ['fingerprint', recipient.fingerprint])

          _.forEach(recipients, function(recipient) {
            recipient.should_encrypt = false
            recipient.fingerprint = null
          })

          this.rows = _.reject(this.rows, row => row.id === recipient.id)
          this.deleteRecipientModalOpen = false
          this.deleteRecipientLoading = false
        })
        .catch(error => {
          this.error()
          this.deleteRecipientLoading = false
          this.deleteRecipientModalOpen = false
        })
    },
    openDeleteRecipientKeyModal(recipient) {
      this.deleteRecipientKeyModalOpen = true
      this.recipientKeyToDelete = recipient
    },
    closeDeleteRecipientKeyModal() {
      this.deleteRecipientKeyModalOpen = false
      this.recipientKeyIdToDelete = null
    },
    deleteRecipientKey(recipient) {
      this.deleteRecipientKeyLoading = true

      axios
        .delete(`/api/v1/recipient-keys/${recipient.id}`)
        .then(response => {
          let recipients = _.filter(this.rows, ['fingerprint', recipient.fingerprint])

          _.forEach(recipients, function(recipient) {
            recipient.should_encrypt = false
            recipient.fingerprint = null
          })
          this.deleteRecipientKeyModalOpen = false
          this.deleteRecipientKeyLoading = false
        })
        .catch(error => {
          if (error.response !== undefined) {
            this.error(error.response.data)
          } else {
            this.error()
          }
          this.deleteRecipientKeyLoading = false
          this.deleteRecipientKeyModalOpen = false
        })
    },
    validateRecipientKey(e) {
      this.errors = {}

      if (!this.recipientKey) {
        this.errors.recipientKey = 'Key required'
      } else if (!this.validKey(this.recipientKey)) {
        this.errors.recipientKey = 'Valid Key required'
      }

      if (!this.errors.recipientKey) {
        this.addRecipientKey()
      }

      e.preventDefault()
    },
    addRecipientKey() {
      this.addRecipientKeyLoading = true

      axios
        .patch(
          `/api/v1/recipient-keys/${this.recipientToAddKey.id}`,
          JSON.stringify({
            key_data: this.recipientKey,
          }),
          {
            headers: { 'Content-Type': 'application/json' },
          }
        )
        .then(({ data }) => {
          this.addRecipientKeyLoading = false

          let recipient = _.find(this.rows, ['id', this.recipientToAddKey.id])
          recipient.should_encrypt = data.data.should_encrypt
          recipient.fingerprint = data.data.fingerprint

          this.recipientKey = ''
          this.addRecipientKeyModalOpen = false
          this.success(
            `Key Successfully Added for ${
              this.recipientToAddKey.email
            }. Make sure to check the fingerprint is correct!`
          )
        })
        .catch(error => {
          this.addRecipientKeyLoading = false
          if (error.response !== undefined) {
            this.error(error.response.data)
          } else {
            this.error()
          }
        })
    },
    turnOnEncryption(id) {
      axios
        .post(
          `/api/v1/encrypted-recipients`,
          JSON.stringify({
            id: id,
          }),
          {
            headers: { 'Content-Type': 'application/json' },
          }
        )
        .then(response => {
          //
        })
        .catch(error => {
          this.error()
        })
    },
    turnOffEncryption(id) {
      axios
        .delete(`/api/v1/encrypted-recipients/${id}`)
        .then(response => {
          //
        })
        .catch(error => {
          this.error()
        })
    },
    openRecipientKeyModal(recipient) {
      this.addRecipientKeyModalOpen = true
      this.recipientToAddKey = recipient
    },
    closeRecipientKeyModal() {
      this.addRecipientKeyModalOpen = false
      this.recipientToAddKey = {}
    },
    validEmail(email) {
      let re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
      return re.test(email)
    },
    validKey(key) {
      let re = /-----BEGIN PGP PUBLIC KEY BLOCK-----([A-Za-z0-9+=\/\n]+)-----END PGP PUBLIC KEY BLOCK-----/i
      return re.test(key)
    },
    clipboardSuccess() {
      this.success('Copied to clipboard')
    },
    clipboardError() {
      this.error('Could not copy to clipboard')
    },
    success(text = '') {
      this.$notify({
        title: 'Success',
        text: text,
        type: 'success',
      })
    },
    error(text = 'An error has occurred, please try again later') {
      this.$notify({
        title: 'Error',
        text: text,
        type: 'error',
      })
    },
  },
}
</script>
