'use strict';

(({ App }) => {
  const { typeOf } = App.Inspector.utils;

  App.Inspector.components.JsonTreeNode = {
    name: 'JsonTreeNode',

    props: {
      lengthResolver: {
        type: Function,
        default: ({ length }) => length,
      },

      keysFilter: {
        type: Function,
        default: ({ keys }) => keys,
      },

      maxLength: {
        type: Number,
        default: Number.MAX_SAFE_INTEGER,
      },

      value: {
        required: true,
        validator(value) {
          return ['null', 'date', 'array', 'object', 'number', 'string', 'boolean', 'undefined'].includes(
            typeOf(value)
          );
        },
      },

      name: {
        type: String,
        required: true,
      },

      path: {
        type: Array,
        required: true,
      },
    },

    data() {
      return {
        isHovered: false,
        isExpanded: false,
      };
    },

    computed: {
      openingBracket() {
        return this.isArray ? '[' : this.isObject ? '{' : '';
      },

      closingBracket() {
        return this.isArray ? ']' : this.isObject ? '}' : '';
      },

      resolvedLength() {
        const { keys, maxLength } = this;

        const resolvedLength =
          typeof this.lengthResolver === 'function'
            ? this.lengthResolver({ keys, value: this.value, isArray: this.isArray, isObject: this.isObject })
            : keys.length;

        return typeof resolvedLength === 'number' ? resolvedLength : keys.length;
      },

      filteredKeys() {
        const { keys, maxLength } = this;

        const filteredKeys =
          typeof this.keysFilter === 'function'
            ? this.keysFilter({ keys, value: this.value, isArray: this.isArray, isObject: this.isObject })
            : keys;

        return (Array.isArray(filteredKeys) ? filteredKeys : keys).slice(0, maxLength);
      },

      isComplex() {
        return this.isObject || this.isArray;
      },

      isObject() {
        return this.type === 'object';
      },

      isArray() {
        return this.type === 'array';
      },

      keys() {
        const keys = this.value ? Object.keys(this.value) : [];
        return this.isArray ? keys.map((key) => parseInt(key, 10)) : keys;
      },

      type() {
        return typeOf(this.value);
      },
    },

    watch: {
      keys: {
        handler() {
          if (false || !this.keys.length) {
            this.collapse();
          }
        },
        immediate: true,
      },

      type: {
        handler() {
          if (true || !this.keys.length) {
            this.collapse();
          }
        },
        immediate: true,
      },
    },

    methods: {
      formatDate(date) {
        return dayjs(date).format('YYYY-MM-DD HH:mm:ss [UTC]Z');
      },

      handleClick() {
        this.isComplex && this.keys.length && this.toggle();
      },

      collapse() {
        this.isExpanded = false;
      },

      expand() {
        this.isExpanded = true;
      },

      toggle() {
        if (this.isExpanded) {
          this.collapse();
        } else {
          this.expand();
        }
      },
    },

    template: /*html*/ `
      <div class="jt-node" :class="[type, { hovered: isHovered, expanded: isExpanded }]" :style="{ '--depth': path.length - 1 }" @mouseover.stop="isHovered = true" @mouseout.stop="isHovered = false" @click.stop="handleClick">
        <div class="jt-node-inner">
          <span v-if="name.length" class="jt-node-label">{{ name }}:&nbsp;</span>
          <span v-else class="jt-node-label"></span>
          <span class="jt-node-value">
            <template v-if="type === 'undefined' || type === 'null'">{{ type }}</template>
            <template v-else-if="type === 'string'">"{{ value }}"</template>
            <template v-else-if="isComplex">
              <span class="jt-node-bracket">{{ openingBracket }}</span>
              <template v-if="!isExpanded">
                <span class="jt-node-preview">{{ resolvedLength }}</span>
                <span class="jt-node-bracket">{{ closingBracket }}</span>
              </template>
            </template>
            <template v-else-if="type === 'date'">{{ formatDate(value) }}</template>
            <template v-else>{{ value }}</template>
          </span>
          <div class="jt-node-actions" @click.stop>
            <button v-if="isComplex && keys.length" type="button" @click="toggle">
              <svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" :style="{ transform: isExpanded ? '' : 'rotate(180deg)' }">
                <path d="M3.51482 9.79281L7.75743 5.55014L12.0001 9.79284L11.2931 10.5L7.75754 6.96435L4.22192 10.4999L3.51482 9.79281Z" />
              </svg>
            </button>
          </div>
        </div>
        <div v-if="isComplex && isExpanded" class="jt-node-nodes">
          <json-tree-node v-for="key in filteredKeys" :key="key" :name="key" :value="value[key]" :path="path.concat(key)" :maxLength="maxLength" :keysFilter="keysFilter" :lengthResolver="lengthResolver" />
          <span v-if="keys.length > filteredKeys.length" class="jt-node-ellipsis">...</span>
          <span class="jt-node-bracket">{{ closingBracket }}</span>
        </div>
      </div>
    `,
  };
})(window);
