<template>
  <div class="w-full relative flex">
    <template v-if="editing">
      <input type="text"
        v-if="singleLine"
        ref="input"
        class="inline-block leading-5 outline-none pl-0 border-0 border-solid border-y w-full border-t-transparent"
        :class="{
          'py-1': !singleLine,
          'inline-edit-placeholder text-sn-grey caret-black': isBlank,
          'border-b-sn-delete-red': error,
          'border-b-sn-science-blue': !error,
        }"
        v-model="newValue"
        :data-e2e="`e2e-IF-${dataE2e}`"
        @keydown="handleKeypress"
        @blur="handleBlur"
        @keyup.escape="cancelEdit && this.atWhoOpened"
        @paste="$emit('paste', e)"
        @focus="setCaretAtEnd"/>
      <textarea v-else
        ref="input"
        class="overflow-hidden leading-5 inline-block outline-none px-0 py-1 border-0 border-solid border-y w-full border-t-transparent mb-0.5"
        :class="{
          'inline-edit-placeholder text-sn-grey caret-black': isBlank,
          'border-sn-delete-red': error,
          'border-sn-science-blue': !error,
        }"
        :placeholder="placeholder"
        v-model="newValue"
        :data-e2e="`e2e-IF-${dataE2e}`"
        @keydown="handleKeypress"
        @blur="handleBlur"
        @keyup.escape="cancelEdit && this.atWhoOpened"
        @paste="$emit('paste', e)"
        @focus="setCaretAtEnd"/>
    </template>
    <div
      v-else
      ref="view"
      class="grid sci-cursor-edit leading-5 border-0 outline-none border-solid border-y border-transparent"
      :class="{ 'text-sn-grey font-normal': isBlank, 'whitespace-pre-line py-1': !singleLine }"
      :data-e2e="`e2e-TX-${dataE2e}`"
      @click="enableEdit($event)"
    >
      <span :class="{'truncate py-1': singleLine }" :title="sa_value || placeholder" v-if="smartAnnotation" v-html="sa_value || placeholder" ></span>
      <span :class="{'truncate py-1': singleLine}" :title="newValue || placeholder" v-else>{{newValue || placeholder}}</span>
    </div>

    <div
      class="mt-2 whitespace-nowrap truncate text-xs font-normal absolute bottom-[-1rem] w-full"
      :title="editing && error ? error : timestamp"
      :class="{'text-sn-delete-red': editing && error}"
      :data-e2e="`e2e-TX-${dataE2e}-timestampError`"
    >
      {{ editing && error ? error : timestamp }}
    </div>
  </div>
</template>

<script>
import UtilsMixin from '../mixins/utils.js';

export default {
  name: 'InlineEdit',
  props: {
    value: { type: String, default: '' },
    sa_value: { type: String },
    allowBlank: { type: Boolean, default: true },
    attributeName: { type: String, required: true },
    characterLimit: { type: Number },
    characterMinLimit: { type: Number },
    timestamp: { type: String },
    placeholder: { type: String },
    autofocus: { type: Boolean, default: false },
    saveOnEnter: { type: Boolean, default: true },
    allowNewLine: { type: Boolean, default: false },
    multilinePaste: { type: Boolean, default: false },
    smartAnnotation: { type: Boolean, default: false },
    editOnload: { type: Boolean, default: false },
    defaultValue: { type: String, default: '' },
    singleLine: { type: Boolean, default: true },
    preventLeavingUntilFilled: { type: Boolean, default: false },
    dataE2e: { type: String, default: '' }
  },
  data() {
    return {
      editing: false,
      dirty: false,
      newValue: ''
    };
  },
  mixins: [UtilsMixin],
  created() {
    this.newValue = this.value || '';
  },
  mounted() {
    this.handleAutofocus();
    if (this.editOnload) {
      this.enableEdit();
    }
  },
  watch: {
    value(newVal, oldVal) {
      if (newVal !== oldVal) {
        this.newValue = newVal;
      }
    },
    editing() {
      this.refreshTexareaHeight();
    },
    newValue() {
      if (this.newValue.length === 0 && this.editing) {
        this.focus();
      }
      this.refreshTexareaHeight();
    },
    autofocus() {
      this.handleAutofocus();
    }
  },
  computed: {
    isBlank() {
      if (typeof this.newValue === 'string') {
        return this.newValue.trim().length === 0;
      }
      return true; // treat as blank for non-string values
    },
    isContentDefault() {
      return this.newValue === this.defaultValue;
    },
    error() {
      if (!this.allowBlank && this.isBlank) {
        if (this.preventLeavingUntilFilled) {
          this.addPreventFromLeaving(document.body);
        }

        return this.i18n.t('inline_edit.errors.blank', { attribute: this.attributeName });
      }
      if (this.characterLimit && this.newValue.length > this.characterLimit) {
        return (
          this.i18n.t(
            'inline_edit.errors.over_limit',
            {
              attribute: this.attributeName,
              limit: this.numberWithSpaces(this.characterLimit)
            }
          )
        );
      }
      if (this.characterMinLimit && this.newValue.length < this.characterMinLimit) {
        return (
          this.i18n.t(
            'inline_edit.errors.below_limit',
            {
              attribute: this.attributeName,
              limit: this.numberWithSpaces(this.characterMinLimit)
            }
          )
        );
      }

      this.removePreventFromLeaving(document.body);
      return false;
    }
  },
  methods: {
    removePreventFromLeaving(domEl) {
      domEl.removeEventListener('click', this.preventClicks, true);
      domEl.removeEventListener('mousedown', this.preventClicks, true);
      domEl.removeEventListener('mouseup', this.preventClicks, true);
    },
    addPreventFromLeaving(domEl) {
      domEl.addEventListener('click', this.preventClicks, true);
      domEl.addEventListener('mousedown', this.preventClicks, true);
      domEl.addEventListener('mouseup', this.preventClicks, true);
    },
    preventClicks(event) {
      event.stopPropagation();
      event.preventDefault();
    },
    handleAutofocus() {
      if (this.autofocus || !this.placeholder && this.isBlank || this.editOnload && this.isBlank) {
        this.enableEdit();
        setTimeout(this.focus, 50);
      }
    },
    handleBlur() {
      if ($('.atwho-view:visible').length) return;
      this.$emit('blur');
      if (this.allowBlank || !this.isBlank) {
        this.$nextTick(this.update);
      } else if (this.isBlank) {
        this.newValue = this.value || '';
      } else {
        this.$emit('delete');
      }
    },
    focus() {
      this.$nextTick(() => {
        if (!this.$refs.input) return;
        this.$refs.input.focus();
      });
    },
    setCaretAtEnd() {
      if (this.isBlank || this.isContentDefault) return;

      const el = this.$refs.input;
      el.focus();
    },
    enableEdit(e) {
      if (e && $(e.target).hasClass('atwho-user-popover')) return;
      if (e && $(e.target).hasClass('sa-link')) return;
      if (e && $(e.target).parent().hasClass('atwho-inserted')) return;

      this.editing = true;
      this.$nextTick(() => {
        this.focus();
        this.$refs.input.value = this.newValue;

        // Select whole content if it is default
        if (this.isContentDefault) {
          const range = document.createRange();
          range.selectNodeContents(this.$refs.input);
          const selection = window.getSelection();
          selection.removeAllRanges();
          selection.addRange(range);
        }
        if (this.smartAnnotation) {
          SmartAnnotation.init($(this.$refs.input), false);
        }
      });
      this.$emit('editingEnabled');
    },
    cancelEdit() {
      this.editing = false;
      this.newValue = this.value || '';
      this.$emit('editingDisabled');
    },
    handleInput(e) {
      this.dirty = true;

      const sel = document.getSelection();
      const offset = sel.anchorOffset;

      this.newValue = this.allowNewLine ? e.target.textContent : e.target.textContent.replace(/^[\n\r]+|[\n\r]+$/g, '');

      sel.collapse(sel.anchorNode, offset);
    },
    handleKeypress(e) {
      this.atWhoOpened = $('.atwho-view:visible').length > 0;
      if (this.atWhoOpened) return;

      if (e.key == 'Escape') {
        this.cancelEdit();
      } else if (e.key == 'Enter' && this.saveOnEnter && e.shiftKey == false) {
        e.preventDefault();
        this.update(e.key);
      } else {
        if (!this.error) this.$emit('error-cleared');
        this.dirty = true;
      }
      this.$emit('keypress', e);
    },
    update(withKey = null) {
      this.refreshTexareaHeight();

      if (!this.dirty && !this.isBlank) {
        this.editing = false;
        return;
      }

      if (this.error) return;
      if (!this.$refs.input) return;
      this.newValue = this.$refs.input.value.trim(); // Fix for smart annotation

      this.editing = false;
      this.$emit('update', this.newValue, withKey);
      this.$emit('editingDisabled');
    },
    refreshTexareaHeight() {
      if (this.editing && !this.singleLine) {
        this.$nextTick(() => {
          if (!this.$refs.input) return;
          this.$refs.input.style.height = `${this.$refs.input.scrollHeight / 2}px`;

          this.$refs.input.style.height = `${this.$refs.input.scrollHeight}px`;
        });
      }
    }
  }
};
</script>
