<template>
  <TfTooltip
    :force-show="visible"
    :show-close="visible"
    :options="{ placement: 'top-start' }"
    trigger="clickToOpen"
    :append-to-body="appendToBody"
    :custom-class="{
      'callout-tooltip': true,
      'is-read': isRead,
    }"
    @documentClick="closeCallOut"
    @hide="closeCallOut"
  >
    <template slot="reference">
      <slot name="reference" />
    </template>
    <section data-test="callout tooltip">
      <template v-if="callouts">
        <header>
          <h5>Benefit call-out</h5>
        </header>
        <template v-if="callouts.length">
          <div class="callout-list">
            <article
              v-for="({
                id,
                user,
                note: calloutNote,
                created_at,
              }, index) in callouts"
              :key="id"
              data-test="callout comment"
            >
              <h6 :data-test="`callout.${index} sender`">
                <span class="user-name">
                  {{ user ? `${user.first_name} ${user.last_name}` : 'Unknown' }}
                </span>
                <span class="date-sent">
                  {{ $TF.DatesUtils.formatSimpleDate(created_at, 'MM/DD/YYYY') }}
                </span>
              </h6>
              <p :data-test="`callout.${index} reason`">
                {{ calloutNote }}
              </p>
            </article>
          </div>
          <AppButton
            v-if="!replyOpen"
            data-test="reply to callout"
            class="reply-button"
            type="primary"
            size="text"
            @click="toggleReply"
          >
            Reply
          </AppButton>
        </template>
        <template v-if="replyOpen">
          <!--
            TW opportunity, we should either create a new component for
            this input with a character counter and limit or add this feature
            to the existing ElInput component. kc 2023-09-26
          -->
          <ElInput
            ref="calloutInput"
            v-model="inputModel"
            :class="{ error: limitExceeded }"
            type="textarea"
            rows="6"
            data-test="enter callout note"
          />
          <div class="footer">
            <div
              class="small-text"
              data-test="callout word count"
            >
              <div
                class="word-count"
                :class="{ error: limitExceeded }"
              >
                {{ charsCountText }}
              </div>
            </div>
            <AppButton
              data-test="save callout"
              icon="fa-solid fa-check"
              size="icon"
              type="success"
              text="save callout"
              :is-disabled="limitExceeded || !hasChanges"
              @click="saveCallout"
            />
          </div>
        </template>
      </template>
      <!-- old version of callout with no benefit comments -->
      <template v-else>
        <header>
          <h5 data-test="callout title">
            Benefit call-out
            <span v-if="isRead"> - read</span>
          </h5>
        </header>
        <p
          v-if="readonly"
          data-test="callout reason"
          v-text="note"
        />
        <template v-else>
          <ElInput
            ref="calloutInput"
            v-model="inputModel"
            :class="{ error: limitExceeded }"
            type="textarea"
            rows="6"
          />
          <div class="footer">
            <div
              class="small-text"
              data-test="callout word count"
            >
              <div
                class="word-count"
                :class="{ error: limitExceeded }"
              >
                {{ charsCountText }}
              </div>
            </div>
            <div class="btn-group">
              <AppButton
                v-if="note"
                data-test="delete callout"
                icon="fa-solid fa-trash"
                size="icon"
                type="danger"
                text="delete callout"
                @click="removeCallOut"
              />
              <AppButton
                data-test="save callout"
                icon="fa-solid fa-check"
                size="icon"
                type="success"
                text="save callout"
                :is-disabled="limitExceeded || !hasChanges"
                @click="saveCallout"
              />
            </div>
          </div>
        </template>
      </template>
    </section>
  </TfTooltip>
</template>

<script>
  /**
   * The callout component is essentially a comment box that is to be attached to a plan design value.
   * Currently, callouts should only be made for values that are deviated from the in-force value.
   * With the benefit callout comments feature, we are removing the need for the plan design value to be deviated.
   *
   * @vuedoc
   * @exports components/CpCallout
   * @category Components
   */
  export default {
    name: 'CpCallout',
    props: {
      /**
       * Whether or not the callout should be appended to the body.
       */
      appendToBody: {
        type: Boolean,
        default: true,
      },
      /**
       * An array of callouts to be displayed in the component.
       */
      callouts: {
        type: Array,
        default: null,
      },
      /**
       * The character limit for the callout.
       */
      charLimit: {
        type: Number,
        default: 256,
      },
      /**
       * @deprecated
       * The text to display in the callout.
       */
      note: {
        type: String,
        default: '',
      },
      /**
       * @deprecated
       * Whether or not the callout is readonly.
       */
      readonly: {
        type: Boolean,
        default: false,
      },
      /**
       * Whether or not the callout is open.
       */
      visible: {
        type: Boolean,
        default: false,
      },
      /**
       * @deprecated
       * Whether or not the callout has been read.
       */
      isRead: {
        type: Boolean,
        default: false,
      },
    },
    data: () => ({
      localNote: null,
      replyOpen: false,
    }),
    computed: {
      /**
       * Compute the remaining characters to be used for validation and template text.
       *
       * @returns {number} charLimit value
       */
      charsLeft() {
        return this.charLimit - this.inputModel.length;
      },
      /**
       * Format the character count to be used within the template.
       *
       * @returns {string} formatted string
       */
      charsCountText() {
        const count = Math.abs(this.charsLeft);
        let text = `${count} character`;

        if (count !== 1) {
          text += 's';
        }

        if (this.limitExceeded) {
          text += ' over limit';
        }

        return text;
      },
      /**
       * Validate the input model against the note param for logic and style purposes.
       *
       * @returns {boolean} chars under charLimit
       */
      hasChanges() {
        return this.inputModel && this.inputModel !== this.note;
      },
      /**
       * Character count validation used for logic and style purposes.
       *
       * @returns {boolean}
       */
      limitExceeded() {
        return this.charsLeft < 0;
      },
      inputModel: {
        /**
         * use localNote if exists otherwise grab from prop
         *
         * @returns {string}
         */
        get() {
          return this.localNote === null ? this.note : this.localNote;
        },
        /**
         * set localNote data prop to new value
         *
         * @param {string} newValue
         */
        set(newValue) {
          this.localNote = newValue;
        },
      },
    },
    watch: {
      /**
       * whenever visible becomes true, auto focus to the input text area.
       *
       * @param {boolean} isVisible
       */
      visible(isVisible) {
        if (isVisible && !this.readonly) {
          if (this.callouts && !this.callouts.length) {
            this.replyOpen = true;
          }

          this.focusOnInput();
        }

        if (!isVisible) {
          this.replyOpen = false;
        }
      },
      /**
       * Whenever a callout is added to the list, thus resizing the tooltip,
       * adjust the position of the tooltip by faking a scroll event so that
       * it continues to point its arrow at the correct element.
       */
      callouts() {
        window.dispatchEvent(new Event('scroll'));
      },
    },
    methods: {
      /**
       * click x closes call out and clears text
       */
      closeCallOut() {
        this.localNote = null;
        this.$emit('update:visible', false);
      },
      /**
       * clears local text in popover
       */
      clearLocalNote() {
        this.localNote = null;
      },
      /**
       * Forces focus on the callout input.
       */
      focusOnInput() {
        this.$nextTick(() => {
          setTimeout(() => {
            if (!this.$refs.calloutInput) {
              return;
            }

            // we have to grab the textarea ref in order to do the next line
            const { textarea } = this.$refs.calloutInput.$refs;
            // the next two lines ensure the text cursor starts at the end of the text value
            textarea.selectionEnd = textarea.value.length;
            textarea.selectionStart = textarea.selectionEnd;
            textarea.focus();
          }, 100);
        });
      },
      /**
       * Toggles the replyOpen state. Without the timeout, the callout
       * closes whenever the user clicks anything that would change the replyOpen state.
       */
      toggleReply() {
        setTimeout(() => {
          this.replyOpen = !this.replyOpen;

          if (this.replyOpen) {
            this.focusOnInput();
          }

          // Fire a fake scroll event in order to force the tooltip to reposition itself after tooltip resize.
          window.dispatchEvent(new Event('scroll'));
        }, 100);
      },
      /**
       * Deletes a comment
       */
      removeCallOut() {
        this.localNote = null;
        this.$emit('removeCallout');
      },
      /**
       * Saves or edits the callout note. If we have an array of callouts,
       * we are using the new benefit comments feature flow.
       *
       */
      saveCallout() {
        if (this.callouts) {
          this.$emit('addCallout', this.localNote);
          this.toggleReply();
          this.clearLocalNote();

          return;
        }

        if (this.hasChanges && !this.limitExceeded) {
          if (this.note) {
            this.$emit('editCallout', this.localNote);
          } else {
            this.$emit('addCallout', this.localNote);
          }
        }
      },
    },
  };
</script>

<style lang="scss" scoped>
  @import 'src/assets/styles/variables';

  section {
    text-align: left;
    color: var(--tf-gray-dark);
    width: 273px;
  }

  header {
    margin-bottom: 10px;
  }

  .callout-list {
    max-height: 300px;
    overflow-y: auto;
    margin-bottom: 10px;
  }

  article {
    .user-name {
      font-weight: 500;
      font-size: 14px;
      margin-bottom: 5px;
    }

    .date-sent {
      color: var(--tf-gray);
      font-size: 12px;
    }

    p {
      color: var(--tf-gray-dark);
      margin: 0 0 10px;
    }
  }

  ::v-deep {
    .el-textarea textarea {
      resize: none;
    }

    .el-textarea__inner {
      width: 273px;
    }
  }

  .is-read {
    ::v-deep .tf-popper {
      border: 1px var(--tf-success) solid;

      /* stylelint-disable selector-max-compound-selectors */
      &[x-placement^='top'] {
        .popper__arrow {
          border-color: var(--tf-success) transparent transparent;
        }
      }

      &[x-placement^='bottom'] {
        .popper__arrow {
          border-color: transparent transparent var(--tf-success);
        }
      }

      &[x-placement^='right'] {
        .popper__arrow {
          border-color: transparent var(--tf-success) transparent transparent;
        }
      }

      &[x-placement^='left'] {
        .popper__arrow {
          border-color: transparent transparent transparent var(--tf-success);
        }
      }
      /* stylelint-enable selector-max-compound-selectors */
    }

    h5 {
      color: var(--tf-success);
    }
  }

  .error {
    &.word-count {
      color: var(--tf-red);
    }

    & ::v-deep .el-textarea__inner {
      border-color: var(--tf-red);
    }
  }

  p {
    color: var(--tf-black);
  }

  .footer {
    display: flex;
    justify-content: space-between;
    margin-top: 10px;
  }
</style>
