<template>
  <section class="campaign">
    <header class="columns">
      <div class="column is-8">
        <p v-if="isEditing" class="tags">
          <b-tag v-if="isEditing" :class="data.status">{{ data.status }}</b-tag>
          <b-tag v-if="data.type === 'optin'" :class="data.type">{{ data.type }}</b-tag>
          <span v-if="isEditing" class="has-text-grey-light is-size-7">
            {{ $t('globals.fields.id') }}: {{ data.id }} /
            {{ $t('globals.fields.uuid') }}: {{ data.uuid }}
          </span>
        </p>
        <h4 v-if="isEditing" class="title is-4">{{ data.name }}</h4>
        <h4 v-else class="title is-4">{{ $t('campaigns.newCampaign') }}</h4>
      </div>

      <div class="column">
        <div class="buttons" v-if="isEditing && canEdit">
          <b-button @click="onSubmit" :loading="loading.campaigns"
            type="is-primary" icon-left="content-save-outline" data-cy="btn-save">
            {{ $t('globals.buttons.saveChanges') }}
          </b-button>
          <b-button v-if="canStart" @click="startCampaign" :loading="loading.campaigns"
            type="is-primary" icon-left="rocket-launch-outline" data-cy="btn-start">
              {{ $t('campaigns.start') }}
          </b-button>
          <b-button v-if="canSchedule" @click="startCampaign" :loading="loading.campaigns"
            type="is-primary" icon-left="clock-start" data-cy="btn-schedule">
              {{ $t('campaigns.schedule') }}
          </b-button>
        </div>
      </div>
    </header>

    <b-loading :active="loading.campaigns"></b-loading>

    <b-tabs type="is-boxed" :animated="false" v-model="activeTab">
      <b-tab-item :label="$tc('globals.terms.campaign')" label-position="on-border"
        icon="rocket-launch-outline">
        <section class="wrap">
          <div class="columns">
            <div class="column is-7">
              <form @submit.prevent="onSubmit">
                <b-field :label="$t('globals.fields.name')" label-position="on-border">
                  <b-input :maxlength="200" :ref="'focus'" v-model="form.name"
                    name="name" :disabled="!canEdit"
                    :placeholder="$t('globals.fields.name')" required></b-input>
                </b-field>

                <b-field :label="$t('campaigns.subject')" label-position="on-border">
                  <b-input :maxlength="200" v-model="form.subject"
                    name="subject" :disabled="!canEdit"
                    :placeholder="$t('campaigns.subject')" required></b-input>
                </b-field>

                <b-field :label="$t('campaigns.fromAddress')" label-position="on-border">
                  <b-input :maxlength="200" v-model="form.fromEmail"
                    name="from_email" :disabled="!canEdit"
                    :placeholder="$t('campaigns.fromAddressPlaceholder')" required></b-input>
                </b-field>

                <list-selector
                  v-model="form.lists"
                  :selected="form.lists"
                  :all="lists.results"
                  :disabled="!canEdit"
                  :label="$t('globals.terms.lists')"
                  :placeholder="$t('campaigns.sendToLists')"
                ></list-selector>

                <b-field :label="$tc('globals.terms.template')" label-position="on-border">
                  <b-select :placeholder="$tc('globals.terms.template')" v-model="form.templateId"
                    name="template" :disabled="!canEdit" required>
                    <option v-for="t in templates" :value="t.id" :key="t.id">{{ t.name }}</option>
                  </b-select>
                </b-field>

                <b-field :label="$tc('globals.terms.messenger')" label-position="on-border">
                  <b-select :placeholder="$tc('globals.terms.messenger')" v-model="form.messenger"
                    name="messenger" :disabled="!canEdit" required>
                    <option v-for="m in messengers"
                      :value="m" :key="m">{{ m }}</option>
                  </b-select>
                </b-field>

                <b-field :label="$t('globals.terms.tags')" label-position="on-border">
                  <b-taginput v-model="form.tags" name="tags" :disabled="!canEdit"
                    ellipsis icon="tag-outline" :placeholder="$t('globals.terms.tags')" />
                </b-field>
                <hr />

                <div class="columns">
                  <div class="column is-4">
                    <b-field :label="$t('campaigns.sendLater')" data-cy="btn-send-later">
                        <b-switch v-model="form.sendLater" :disabled="!canEdit" />
                    </b-field>
                  </div>
                  <div class="column">
                    <br />
                    <b-field v-if="form.sendLater" data-cy="send_at"
                      :message="form.sendAtDate ? $utils.duration(Date(), form.sendAtDate) : ''">
                      <b-datetimepicker
                        v-model="form.sendAtDate"
                        :disabled="!canEdit"
                        :placeholder="$t('campaigns.dateAndTime')"
                        icon="calendar-clock"
                        :timepicker="{ hourFormat: '24' }"
                        :datetime-formatter="formatDateTime"
                        horizontal-time-picker>
                      </b-datetimepicker>
                    </b-field>
                  </div>
                </div>
                <hr />

                <b-field v-if="isNew">
                  <b-button native-type="submit" type="is-primary"
                    :loading="loading.campaigns" data-cy="btn-continue">
                    {{ $t('campaigns.continue') }}
                  </b-button>
                </b-field>
              </form>
            </div>
            <div class="column is-4 is-offset-1">
              <br />
              <div class="box">
                <h3 class="title is-size-6">{{ $t('campaigns.sendTest') }}</h3>
                  <b-field :message="$t('campaigns.sendTestHelp')">
                    <b-taginput v-model="form.testEmails"
                      :before-adding="$utils.validateEmail" :disabled="this.isNew"
                      ellipsis icon="email-outline" :placeholder="$t('campaigns.testEmails')" />
                  </b-field>
                  <b-field>
                    <b-button @click="sendTest" :loading="loading.campaigns" :disabled="this.isNew"
                      type="is-primary" icon-left="email-outline">
                      {{ $t('campaigns.send') }}
                    </b-button>
                  </b-field>
              </div>
            </div>
          </div>
        </section>
      </b-tab-item><!-- campaign -->

      <b-tab-item :label="$t('campaigns.content')" icon="text" :disabled="isNew">
        <editor
          v-model="form.content"
          :id="data.id"
          :title="data.name"
          :contentType="data.contentType"
          :body="data.body"
          :disabled="!canEdit"
        />

        <div v-if="canEdit && form.content.contentType !== 'plain'" class="alt-body">
          <p class="is-size-6 has-text-grey has-text-right">
            <a v-if="form.altbody === null" href="#" @click.prevent="addAltBody">
              <b-icon icon="text" size="is-small" /> {{ $t('campaigns.addAltText') }}
            </a>
            <a v-else href="#" @click.prevent="$utils.confirm(null, removeAltBody)">
              <b-icon icon="trash-can-outline" size="is-small" />
              {{ $t('campaigns.removeAltText') }}
            </a>
          </p>
          <br />
          <b-input v-if="form.altbody !== null" v-model="form.altbody"
            type="textarea" :disabled="!canEdit" />
        </div>
      </b-tab-item><!-- content -->
    </b-tabs>
  </section>
</template>

<script>
import Vue from 'vue';
import { mapState } from 'vuex';
import dayjs from 'dayjs';
import htmlToPlainText from 'textversionjs';

import ListSelector from '../components/ListSelector.vue';
import Editor from '../components/Editor.vue';

export default Vue.extend({
  components: {
    ListSelector,
    Editor,
  },

  data() {
    return {
      isNew: false,
      isEditing: false,
      activeTab: 0,

      data: {},

      // IDs from ?list_id query param.
      selListIDs: [],

      // Binds form input values.
      form: {
        name: '',
        subject: '',
        fromEmail: '',
        templateId: 0,
        lists: [],
        tags: [],
        sendAt: null,
        content: { contentType: 'richtext', body: '' },
        altbody: null,

        // Parsed Date() version of send_at from the API.
        sendAtDate: null,
        sendLater: false,

        testEmails: [],
      },
    };
  },

  methods: {
    formatDateTime(s) {
      return dayjs(s).format('YYYY-MM-DD HH:mm');
    },

    addAltBody() {
      this.form.altbody = htmlToPlainText(this.form.content.body);
    },

    removeAltBody() {
      this.form.altbody = null;
    },

    onSubmit() {
      if (this.isNew) {
        this.createCampaign();
      } else {
        this.updateCampaign();
      }
    },

    getCampaign(id) {
      return this.$api.getCampaign(id).then((data) => {
        this.data = data;
        this.form = {
          ...this.form,
          ...data,

          // The structure that is populated by editor input event.
          content: { contentType: data.contentType, body: data.body },
        };

        if (data.sendAt !== null) {
          this.form.sendLater = true;
          this.form.sendAtDate = dayjs(data.sendAt).toDate();
        }
      });
    },

    sendTest() {
      const data = {
        id: this.data.id,
        name: this.form.name,
        subject: this.form.subject,
        lists: this.form.lists.map((l) => l.id),
        from_email: this.form.fromEmail,
        messenger: this.form.messenger,
        type: 'regular',
        tags: this.form.tags,
        template_id: this.form.templateId,
        content_type: this.form.content.contentType,
        body: this.form.content.body,
        altbody: this.form.content.contentType !== 'plain' ? this.form.altbody : null,
        subscribers: this.form.testEmails,
      };

      this.$api.testCampaign(data).then(() => {
        this.$utils.toast(this.$t('campaigns.testSent'));
      });
      return false;
    },

    createCampaign() {
      const data = {
        name: this.form.name,
        subject: this.form.subject,
        lists: this.form.lists.map((l) => l.id),
        from_email: this.form.fromEmail,
        content_type: 'richtext',
        messenger: 'email',
        type: 'regular',
        tags: this.form.tags,
        template_id: this.form.templateId,
        // body: this.form.body,
      };

      this.$api.createCampaign(data).then((d) => {
        this.$router.push({ name: 'campaign', hash: '#content', params: { id: d.id } });
      });
      return false;
    },

    async updateCampaign(typ) {
      const data = {
        name: this.form.name,
        subject: this.form.subject,
        lists: this.form.lists.map((l) => l.id),
        from_email: this.form.fromEmail,
        messenger: this.form.messenger,
        type: 'regular',
        tags: this.form.tags,
        send_later: this.form.sendLater,
        send_at: this.form.sendLater ? this.form.sendAtDate : null,
        template_id: this.form.templateId,
        content_type: this.form.content.contentType,
        body: this.form.content.body,
        altbody: this.form.content.contentType !== 'plain' ? this.form.altbody : null,
      };

      let typMsg = 'globals.messages.updated';
      if (typ === 'start') {
        typMsg = 'campaigns.started';
      }

      // This promise is used by startCampaign to first save before starting.
      return new Promise((resolve) => {
        this.$api.updateCampaign(this.data.id, data).then((d) => {
          this.data = d;
          this.$utils.toast(this.$t(typMsg, { name: d.name }));
          resolve();
        });
      });
    },

    // Starts or schedule a campaign.
    startCampaign() {
      let status = '';
      if (this.canStart) {
        status = 'running';
      } else if (this.canSchedule) {
        status = 'scheduled';
      } else {
        return;
      }

      this.$utils.confirm(null,
        () => {
          // First save the campaign.
          this.updateCampaign().then(() => {
            // Then start/schedule it.
            this.$api.changeCampaignStatus(this.data.id, status).then(() => {
              this.$router.push({ name: 'campaigns' });
            });
          });
        });
    },
  },

  computed: {
    ...mapState(['settings', 'loading', 'lists', 'templates']),

    canEdit() {
      return this.isNew
        || this.data.status === 'draft' || this.data.status === 'scheduled';
    },

    canSchedule() {
      return this.data.status === 'draft' && this.data.sendAt;
    },

    canStart() {
      return this.data.status === 'draft' && !this.data.sendAt;
    },

    selectedLists() {
      if (this.selListIDs.length === 0 || !this.lists.results) {
        return [];
      }

      return this.lists.results.filter((l) => this.selListIDs.indexOf(l.id) > -1);
    },

    messengers() {
      return ['email', ...this.settings.messengers.map((m) => m.name)];
    },
  },

  watch: {
    selectedLists() {
      this.form.lists = this.selectedLists;
    },
  },

  mounted() {
    this.form.fromEmail = this.settings['app.from_email'];

    const { id } = this.$route.params;

    // New campaign.
    if (id === 'new') {
      this.isNew = true;

      if (this.$route.query.list_id) {
        // Multiple list_id query params.
        let strIds = [];
        if (typeof this.$route.query.list_id === 'object') {
          strIds = this.$route.query.list_id;
        } else {
          strIds = [this.$route.query.list_id];
        }

        this.selListIDs = strIds.map((v) => parseInt(v, 10));
      }
    } else {
      const intID = parseInt(id, 10);
      if (intID <= 0 || Number.isNaN(intID)) {
        this.$utils.toast(this.$t('campaigns.invalid'));
        return;
      }

      this.isEditing = true;
    }

    // Get templates list.
    this.$api.getTemplates().then((data) => {
      if (data.length > 0) {
        if (!this.form.templateId) {
          this.form.templateId = data.find((i) => i.isDefault === true).id;
        }
      }
    });

    // Fetch campaign.
    if (this.isEditing) {
      this.getCampaign(id).then(() => {
        if (this.$route.hash === '#content') {
          this.activeTab = 1;
        }
      });
    } else {
      this.form.messenger = 'email';
    }

    this.$nextTick(() => {
      this.$refs.focus.focus();
    });
  },
});
</script>
