'use strict';

(({ App }) => {
  const { utils, components } = App.Inspector;
  const { $, i18n, copy, getTreeProps } = utils;

  const Preview = new Vue({
    i18n,

    name: 'Preview',

    components: { ...components },

    props: {
      showTimeout: {
        type: Number,
        default: 0,
      },
      hideTimeout: {
        type: Number,
        default: 250,
      },
    },

    data() {
      return {
        data: {
          title: '',
          value: null,
          type: 'json',
          calculateNoTruncate: null
        },
        $ref: null,
        $top: null,
        popper: null,
        mutationObserver: null,
        showTimer: null,
        hideTimer: null,
        isVisible: false,
        isUpdating: false,
        arrowOffset: [0, 5],
        treeProps: getTreeProps(),
      };
    },

    computed: {
      style() {
        const { isUpdating, arrowOffset } = this;

        return {
          '--arrow-offset-skidding': `${arrowOffset[0]}px`,
          '--arrow-offset-distance': `${arrowOffset[1]}px`,
          'visibility': isUpdating ? 'hidden' : 'visible',
        };
      },
    },

    created() {
      window.addEventListener('scroll', this.hide);
    },

    destroyed() {
      window.removeEventListener('scroll', this.hide);
    },

    methods: {
      async copyAll() {
        if(this.data.calculateNoTruncate) {
          const { result, error } = await this.data.calculateNoTruncate()
          if(!error) {
            copy(result)
          }
        } else {
          copy(this.data.value)
        }
      },

      hide() {
        if (!this.isVisible) return;
        this.stopShowTimer();
        this.stopHideTimer();

        $.removeClass(this.$ref, 'preview-target');

        let task = this.$ref.closest('.taskcontainer')
        if(task) {
          $.removeClass(task, "preview-target-container")
        }

        if (this.mutationObserver) {
          this.mutationObserver.disconnect();
        }
        
        this.isUpdating = false;
        this.isVisible = false;
        this.$top = null;
        this.$ref = null;

        this.popper && this.popper.destroy();
        this.popper = null;
      },

      stopShowTimer() {
        clearTimeout(this.showTimer);
        this.showTimer = null;
      },

      stopHideTimer() {
        clearTimeout(this.hideTimer);
        this.hideTimer = null;
      },

      startHideTimer() {
        this.stopHideTimer();
        this.hideTimer = setTimeout(() => {
          if (
            $.matches(this.$top, ':hover') ||
            $.matches(this.$ref, ':hover') ||
            $.matches(this.$refs.root, ':hover')
          ) {
            this.startHideTimer();
          } else {
            this.hide();
          }
        }, this.hideTimeout);
      },

      showInternal($ref, $top) {
        let previewRootInitial = document.getElementsByClassName("jt-root")[0]
        if(previewRootInitial) {
          previewRootInitial.style.minWidth = "0px"
          previewRootInitial.style.minHeight = "0px"
        }

        $.addClass($ref, 'preview-target');

        let task = $ref.closest('.taskcontainer')
        if(task) {
          $.addClass(task, "preview-target-container")
        }
        
        this.isUpdating = true;
        this.isVisible = true;
        this.$top = $top;
        this.$ref = $ref;

        this.popper = Popper.createPopper($ref, this.$refs.root, {
          modifiers: [
            { name: 'offset', options: { offset: this.arrowOffset } },
            { name: 'arrow', options: { padding: { left: 1, right: 1 } } },
            { name: 'flip', options: { allowedAutoPlacements: ['top', 'bottom'] } },
          ],
          placement: 'auto',
          strategy: 'fixed',
        });


        this.$nextTick(function(){
          let previewRoot = document.getElementsByClassName("jt-root")[0]
          if(previewRoot) {
            previewRoot.style.minWidth = previewRoot.offsetWidth + "px"
            previewRoot.style.minHeight = previewRoot.offsetHeight + "px"
          }
        })

        let self = this
        // Set up the MutationObserver
        // Whenever the tooltip content (DOM subtree) changes, we'll call update()
        this.mutationObserver = new MutationObserver(() => {
          if (self.popper) {
            self.popper.update();
            this.$nextTick(function(){
              let previewRoot = document.getElementsByClassName("jt-root")[0]
              if(previewRoot) {
                previewRoot.style.minWidth = previewRoot.offsetWidth + "px"
                previewRoot.style.minHeight = previewRoot.offsetHeight + "px"
              }
            })
          }
        });

        // Observe for childList changes (text, elements), and subtree changes
        this.mutationObserver.observe(this.$refs.root, {
          childList: true,
          subtree: true,
        });

        this.$nextTick(() => (this.isUpdating = false));
      },

      show($ref, $top, props = {}) {
        // By default the $top node is the same as the $ref,
        // but in case if there is an overlapping, we can use the
        // first one to check the hover state and customize our logic
        if (!$ref || !props || typeof props !== 'object') return;
        if ($ref === this.$ref) return;

        this.hide();
        this.stopShowTimer();
        this.showTimer = setTimeout(() => {
          this.stopShowTimer();

          if ($.matches($ref, ':hover') || $.matches($top, ':hover')) {
            this.data = Object.assign({}, this.data, props);
            this.showInternal($ref, $top);
            this.startHideTimer();
          }
        }, this.showTimeout);
      },
    },

    template: /* html */ `
      <div ref="root" id="preview" :style="style" class="preview" v-show="isVisible" @mouseenter="stopHideTimer" @mouseleave="startHideTimer">
        <div class="preview-root">
          <div class="preview-header">
            <div class="preview-title" v-html="data.title"></div>
            <button type="button" class="preview-copy" :title="$t('copy')" @click="copyAll">
              <svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
                <path d="M12 3V0H2v12h4v3h9V3h-3Zm-6 8H3V1h8v2H6v8Zm8 3H7V4h7v10Z" fill="#606060" />
              </svg>
            </button>
          </div>
          <div class="preview-content" :class="data.type">
            <img v-if="data.type === 'image'" draggable="false" :src="'data:image/png;base64, ' + data.value" />
            <span v-else-if="data.type === 'error'">{{ data.value }}</span>
            <json-tree-root v-else v-bind="treeProps" :value="data.value" />
          </div>
        </div>
        <div class="preview-arrow" data-popper-arrow></div>
      </div>
    `,
  });

  const preview = Preview.$mount('#preview', {
    showTimeout: 0,
    hideTimeout: 250,
  });

  App.Inspector.showPreview = preview.show.bind(preview);
})(window);
