<template>
  <div class="step-checklist-container" >
    <div class="step-element-header" :class="{ 'editing-name': editingName, 'no-hover': !element.attributes.orderable.urls.update_url }">
      <div v-if="reorderElementUrl" class="step-element-grip" @click="$emit('reorder')">
        <i class="fas fas-rotated-90 fa-exchange-alt"></i>
      </div>
      <div v-else class="step-element-grip-placeholder"></div>
      <div class="step-element-name">
        <InlineEdit
          :class="{ 'step-element--locked': !element.attributes.orderable.urls.update_url }"
          :value="element.attributes.orderable.name"
          :sa_value="element.attributes.orderable.sa_name"
          :characterLimit="10000"
          :placeholder="''"
          :allowBlank="false"
          :autofocus="editingName"
          :smartAnnotation="true"
          :attributeName="`${i18n.t('Checklist')} ${i18n.t('name')}`"
          @editingEnabled="editingName = true"
          @editingDisabled="editingName = false"
          @update="updateName"
        />
      </div>
      <div class="step-element-controls">
        <button v-if="element.attributes.orderable.urls.update_url" class="btn icon-btn btn-light" @click="editingName = true" tabindex="0">
          <i class="fas fa-pen"></i>
        </button>
        <button v-if="element.attributes.orderable.urls.duplicate_url" class="btn icon-btn btn-light" tabindex="0" @click="duplicateElement">
          <i class="fas fa-clone"></i>
        </button>
        <button v-if="element.attributes.orderable.urls.delete_url" class="btn icon-btn btn-light" @click="showDeleteModal" tabindex="0">
          <i class="fas fa-trash"></i>
        </button>
      </div>
    </div>
    <div v-if="element.attributes.orderable.urls.create_item_url || orderedChecklistItems.length > 0" class="step-checklist-items">
      <Draggable
        v-model="checklistItems"
        :ghostClass="'step-checklist-item-ghost'"
        :dragClass="'step-checklist-item-drag'"
        :chosenClass="'step-checklist-item-chosen'"
        :handle="'.step-element-grip'"
        :disabled="editingItem || checklistItems.length < 2 || !element.attributes.orderable.urls.reorder_url"
        @start="startReorder"
        @end="endReorder"
      >
        <ChecklistItem
          v-for="checklistItem in orderedChecklistItems"
          :key="checklistItem.attributes.id"
          :checklistItem="checklistItem"
          :locked="locked"
          :reorderChecklistItemUrl="element.attributes.orderable.urls.reorder_url"
          :inRepository="inRepository"
          :draggable="checklistItems.length > 1"
          @editStart="editingItem = true"
          @editEnd="editingItem = false"
          @update="saveItem"
          @toggle="saveItemChecked"
          @removeItem="removeItem"
          @component:delete="removeItem"
          @multilinePaste="handleMultilinePaste"
        />
      </Draggable>
      <div v-if="element.attributes.orderable.urls.create_item_url"
           class="btn btn-light step-checklist-add-item"
           tabindex="0"
           @keyup.enter="addItem"
           @click="addItem">
        <i class="fas fa-plus"></i>
        {{ i18n.t('protocols.steps.insert.checklist_item') }}
      </div>
    </div>
    <div v-else class="empty-checklist-element">
      {{ i18n.t("protocols.steps.checklist.empty_checklist") }}
    </div>
    <deleteElementModal v-if="confirmingDelete" @confirm="deleteElement" @cancel="closeDeleteModal"/>
  </div>
</template>

 <script>
  import DeleteMixin from 'vue/protocol/mixins/components/delete.js'
  import DuplicateMixin from 'vue/protocol/mixins/components/duplicate.js'
  import deleteElementModal from 'vue/protocol/modals/delete_element.vue'
  import InlineEdit from 'vue/shared/inline_edit.vue'
  import ChecklistItem from 'vue/protocol/step_elements/checklistItem.vue'
  import Draggable from 'vuedraggable'

  export default {
    name: 'Checklist',
    components: { deleteElementModal, InlineEdit, ChecklistItem, Draggable },
    mixins: [DeleteMixin, DuplicateMixin],
    props: {
      element: {
        type: Object,
        required: true
      },
      inRepository: {
        type: Boolean,
        required: true
      },
      reorderElementUrl: {
        type: String
      },
      isNew: {
        type: Boolean,
        default: false
      }
    },
    data() {
      return {
        checklistItems: [],
        linesToPaste: 0,
        editingName: false,
        reordering: false,
        editingItem: false
      }
    },
    created() {
      this.initChecklistItems();

      if (this.isNew) {
        this.addItem();
      }
    },
    watch: {
      element() {
        this.initChecklistItems();
      }
    },
    computed: {
      orderedChecklistItems() {
        return this.checklistItems.map((item, index) => {
          return { attributes: {...item.attributes, position: index } }
        });
      },
      pastingMultiline() {
        return this.linesToPaste > 0;
      },
      locked() {
        return this.reordering || this.editingName || !this.element.attributes.orderable.urls.update_url
      }
    },
    methods: {
      initChecklistItems() {
        this.checklistItems = this.element.attributes.orderable.checklist_items.map((item, index) => {
          return { attributes: {...item, position: index } }
        });
      },
      updateName(name) {
        this.element.attributes.orderable.name = name;
        this.editingName = false;
        this.update(false);
      },
      update(skipRequest = true) {
        this.element.attributes.orderable.checklist_items =
          this.checklistItems.map((i) => i.attributes);

        this.$emit('update', this.element, skipRequest);
      },
      postItem(item, callback) {
        $.post(this.element.attributes.orderable.urls.create_item_url, item).success((result) => {
          this.checklistItems.splice(
            result.data.attributes.position,
            1,
            { attributes: { ...result.data.attributes, id: result.data.id } }
          );

          if(callback) callback();
        }).error(() => {
          HelperModule.flashAlertMsg(this.i18n.t('errors.general'), 'danger');
        });

        this.update();
      },
      saveItem(item) {
        if (item.attributes.id) {
          $.ajax({
            url: item.attributes.urls.update_url,
            type: 'PATCH',
            data: item,
            success: (result) => {
              let updatedItem = this.checklistItems[item.attributes.position]
              updatedItem.attributes = result.data.attributes
              updatedItem.attributes.id = item.attributes.id
              this.$set(this.checklistItems, item.attributes.position, updatedItem)
            },
            error: () => HelperModule.flashAlertMsg(this.i18n.t('errors.general'), 'danger')
          });
        } else {
          // create item, then append next one
          this.postItem(item, this.addItem);
        }
        this.update(true);
      },
      saveItemChecked(item) {
        $.ajax({
          url: item.attributes.urls.toggle_url,
          type: 'PATCH',
          data: { attributes: { checked: item.attributes.checked } },
          success: (result) => {
            let updatedItem = this.checklistItems[item.attributes.position]
            updatedItem.attributes = result.data.attributes
            updatedItem.attributes.id = item.attributes.id
            this.$set(this.checklistItems, item.attributes.position, updatedItem)
          },
          error: () => HelperModule.flashAlertMsg(this.i18n.t('errors.general'), 'danger')
        });
      },
      addItem() {
        this.checklistItems.push(
          {
            attributes: {
              text: '',
              checked: false,
              position: this.checklistItems.length,
              isNew: true
            }
          }
        );
      },
      removeItem(position) {
        this.checklistItems.splice(position, 1);
        this.update();
      },
      startReorder() {
        this.reordering = true;
      },
      endReorder() {
        this.reordering = false;
        this.saveItemOrder();
      },
      saveItemOrder() {
        let checklistItemPositions =
          {
            checklist_item_positions: this.orderedChecklistItems.map(
              (i) => [i.attributes.id, i.attributes.position]
            )
          };

        $.ajax({
          type: "POST",
          url: this.element.attributes.orderable.urls.reorder_url,
          data: JSON.stringify(checklistItemPositions),
          contentType: "application/json",
          dataType: "json",
          error: (() => HelperModule.flashAlertMsg(this.i18n.t('errors.general'), 'danger')),
          success: (() => this.update())
        });
      },
      handleMultilinePaste(data) {
        this.linesToPaste = data.length;
        let nextPosition = this.checklistItems.length - 1;

        // we need to post items to API in the right order, to avoid positions breaking
        let synchronousPost = (index) => {
          if(index === data.length) return;

          let item = {
            attributes: {
              text: data[index],
              checked: false,
              position: nextPosition + index
            }
          };

          this.linesToPaste -= 1;
          this.postItem(item, () => synchronousPost(index + 1));
        };

        synchronousPost(0);
      }
    }
  }
</script>