import debounce from 'lodash/debounce';
import { translate } from '../../../utils/i18n';
import GlAvatar from '../avatar/avatar';
import GlDisclosureDropdown from '../new_dropdowns/disclosure/disclosure_dropdown';
import { GlTooltipDirective } from '../../../directives/tooltip/tooltip';
import { breadCrumbSizeOptions } from '../../../utils/constants';
import ClipboardButton from '../../shared_components/clipboard_button/clipboard_button';
import GlBreadcrumbItem from './breadcrumb_item';
import __vue_normalize__ from 'vue-runtime-helpers/dist/normalize-component.js';

var script = {
  name: 'GlBreadcrumb',
  components: {
    GlBreadcrumbItem,
    GlAvatar,
    GlDisclosureDropdown,
    ClipboardButton
  },
  directives: {
    GlTooltip: GlTooltipDirective
  },
  inheritAttrs: false,
  props: {
    /**
     * The breadcrumb items to be displayed as links.
     */
    items: {
      type: Array,
      required: true,
      default: () => [{
        text: '',
        href: ''
      }],
      validator: items => {
        return items.every(item => {
          const keys = Object.keys(item);
          return keys.includes('text') && item.text && (keys.includes('href') || keys.includes('to'));
        });
      }
    },
    /**
     * Accessible label for the breadcrumb navigation.
     */
    ariaLabel: {
      type: String,
      required: false,
      default: 'Breadcrumb'
    },
    /**
     * The label for the collapsed dropdown toggle. Screen-reader only.
     */
    showMoreLabel: {
      type: String,
      required: false,
      default: () => translate('GlBreadcrumb.showMoreLabel', 'Show more breadcrumbs')
    },
    /**
     * Allows to disable auto-resize behavior. Items will then overflow their container instead of being collapsed into a dropdown.
     */
    autoResize: {
      type: Boolean,
      required: false,
      default: true
    },
    /**
     * Size of the breadcrumb item. Use `sm` for page breadcrumbs.
     */
    size: {
      type: String,
      required: false,
      default: breadCrumbSizeOptions.sm,
      validator: value => Object.keys(breadCrumbSizeOptions).includes(value)
    },
    /**
     * Copy to clipboard button for breadcrumbs path.
     */
    showClipboardButton: {
      type: Boolean,
      required: false,
      default: false
    },
    /**
     * Custom path for copy to clipboard button. By default, it resolves to all items text values with `/` separator.
     */
    pathToCopy: {
      type: String,
      required: false,
      default: null
    },
    /**
     * Custom tooltip text for clipboard button.
     */
    clipboardTooltipText: {
      type: String,
      required: false,
      default: null
    }
  },
  data() {
    return {
      fittingItems: [...this.items],
      // array of items that fit on the screen
      overflowingItems: [],
      // array of items that didn't fit and were put in a dropdown instead
      totalBreadcrumbsWidth: 0,
      // the total width of all breadcrumb items combined
      widthPerItem: [],
      // array with the individual widths of each breadcrumb item
      dropdownWidth: 0,
      // the width of the breadcrumb item containing the dropdown toggle
      clipboardButtonWidth: 0,
      // the width of the clipboard button at the end of breadcrumbs
      resizeDone: false // to apply some CSS only during/after resizing
    };
  },
  computed: {
    hasCollapsible() {
      return this.overflowingItems.length > 0;
    },
    breadcrumbStyle() {
      return this.resizeDone ? {} : {
        opacity: 0
      };
    },
    itemClass() {
      if (this.resizeDone && this.fittingItems.length === 1) {
        return 'gl-breadcrumb-only-item';
      }
      return '';
    },
    dropdownSize() {
      return this.size === 'sm' ? 'small' : 'medium';
    },
    avatarSize() {
      return this.size === 'sm' ? 16 : 24;
    },
    clipboardButtonText() {
      if (this.pathToCopy) return this.pathToCopy;
      const items = Array.from(this.items, item => item.text);
      return items.join('/');
    }
  },
  watch: {
    items: {
      handler: 'measureAndMakeBreadcrumbsFit',
      deep: true
    },
    autoResize(newValue) {
      if (newValue) this.enableAutoResize();else this.disableAutoResize();
    }
  },
  created() {
    this.debounceMakeBreadcrumbsFit = debounce(this.makeBreadcrumbsFit, 25);
  },
  mounted() {
    if (this.autoResize) {
      this.enableAutoResize();
    } else {
      this.resizeDone = true;
    }
    this.clipboardButtonWidth = this.showClipboardButton ? this.$refs.clipboardButton.$el.clientWidth : 0;
  },
  beforeDestroy() {
    this.disableAutoResize();
  },
  methods: {
    resetItems() {
      this.fittingItems = [...this.items];
      this.overflowingItems = [];
    },
    async measureAndMakeBreadcrumbsFit() {
      this.resetItems();
      if (!this.autoResize) return;
      this.resizeDone = false;

      // Wait for DOM update so all items get rendered and can be measured.
      await this.$nextTick();
      this.totalBreadcrumbsWidth = 0;
      if (!this.$refs.breadcrumbs) return;
      this.$refs.breadcrumbs.forEach((b, index) => {
        const width = b.$el.clientWidth;
        this.totalBreadcrumbsWidth += width;
        this.widthPerItem[index] = width;
      });
      this.totalBreadcrumbsWidth += this.clipboardButtonWidth;

      // The dropdown gets rendered during `!resizeDone` so we can measure its real width here.
      this.dropdownWidth = this.$refs.dropdown.clientWidth;
      this.makeBreadcrumbsFit();
    },
    makeBreadcrumbsFit() {
      this.resizeDone = false;
      this.resetItems();
      const containerWidth = this.$el.clientWidth;
      if (this.totalBreadcrumbsWidth > containerWidth) {
        // Not all breadcrumb items fit. Start moving items over to the dropdown.
        const startSlicingAt = 0;

        // The last item will never be moved into the dropdown.
        const stopSlicingAt = this.items.length - 1;
        let widthNeeded = this.totalBreadcrumbsWidth;
        for (let index = startSlicingAt; index < stopSlicingAt; index += 1) {
          // Move one breadcrumb item into the dropdown
          this.overflowingItems.push(this.fittingItems[startSlicingAt]);
          this.fittingItems.splice(startSlicingAt, 1);
          widthNeeded -= this.widthPerItem[index];

          // Does it fit now? Then stop.
          if (widthNeeded + this.dropdownWidth < containerWidth) break;
        }
      }
      this.resizeDone = true;
    },
    isLastItem(index) {
      return index === this.fittingItems.length - 1;
    },
    getAriaCurrentAttr(index) {
      return this.isLastItem(index) ? 'page' : false;
    },
    enableAutoResize() {
      this.resizeObserver || (this.resizeObserver = new ResizeObserver(this.debounceMakeBreadcrumbsFit));
      this.resizeObserver.observe(this.$el);
      this.measureAndMakeBreadcrumbsFit();
    },
    disableAutoResize() {
      if (this.resizeObserver) {
        this.resizeObserver.unobserve(this.$el);
        this.resizeObserver = null;
      }
      this.resetItems();
    }
  }
};

/* script */
const __vue_script__ = script;

/* template */
var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('nav',{staticClass:"gl-breadcrumbs",style:(_vm.breadcrumbStyle),attrs:{"aria-label":_vm.ariaLabel}},[_c('ol',_vm._g(_vm._b({staticClass:"gl-breadcrumb-list breadcrumb"},'ol',_vm.$attrs,false),_vm.$listeners),[(_vm.hasCollapsible || !_vm.resizeDone)?_c('li',{ref:"dropdown",class:("gl-breadcrumb-item gl-breadcrumb-item-" + _vm.size)},[_c('gl-disclosure-dropdown',{attrs:{"items":_vm.overflowingItems,"toggle-text":_vm.showMoreLabel,"fluid-width":"","text-sr-only":"","no-caret":"","icon":"ellipsis_h","size":_vm.dropdownSize}})],1):_vm._e(),_vm._v(" "),_vm._l((_vm.fittingItems),function(item,index){return _c('gl-breadcrumb-item',{key:index,ref:"breadcrumbs",refInFor:true,class:_vm.itemClass,attrs:{"text":item.text,"href":item.href,"to":item.to,"size":_vm.size,"aria-current":_vm.getAriaCurrentAttr(index)},scopedSlots:_vm._u([{key:"default",fn:function(){return [(item.avatarPath)?_c('gl-avatar',{staticClass:"gl-breadcrumb-avatar-tile gl-border gl-mr-2 !gl-rounded-default",attrs:{"src":item.avatarPath,"size":_vm.avatarSize,"aria-hidden":"true","shape":"rect","data-testid":"avatar"}}):_vm._e(),_c('span',{staticClass:"gl-align-middle"},[_vm._v(_vm._s(item.text))])]},proxy:true}],null,true)})}),_vm._v(" "),(_vm.showClipboardButton)?_c('li',{staticClass:"gl-breadcrumb-clipboard-button"},[_c('clipboard-button',_vm._b({ref:"clipboardButton",staticClass:"gl-ml-2",attrs:{"data-testid":"copy-to-clipboard-button","text":_vm.clipboardButtonText,"size":_vm.dropdownSize}},'clipboard-button',_vm.clipboardTooltipText ? { title: _vm.clipboardTooltipText } : {},false))],1):_vm._e()],2)])};
var __vue_staticRenderFns__ = [];

  /* style */
  const __vue_inject_styles__ = undefined;
  /* scoped */
  const __vue_scope_id__ = undefined;
  /* module identifier */
  const __vue_module_identifier__ = undefined;
  /* functional template */
  const __vue_is_functional_template__ = false;
  /* style inject */
  
  /* style inject SSR */
  
  /* style inject shadow dom */
  

  
  const __vue_component__ = /*#__PURE__*/__vue_normalize__(
    { render: __vue_render__, staticRenderFns: __vue_staticRenderFns__ },
    __vue_inject_styles__,
    __vue_script__,
    __vue_scope_id__,
    __vue_is_functional_template__,
    __vue_module_identifier__,
    false,
    undefined,
    undefined,
    undefined
  );

export { __vue_component__ as default };
