import {
  ref,
  Ref,
  onMounted,
  onBeforeUnmount,
  defineComponent,
  computed,
} from 'vue';
import debounce from 'lodash/debounce';
import { useRootElement } from '../use-root-element';
import { useInline } from './use-inline';
import {
  getSelection,
  getAnchorElementForSelection,
  getRangeFromSelection,
  getRect,
} from './selection';

import './InlineToolbar.scss';

export const SbInlineToolbar = defineComponent({
  name: 'sb-inlinetoolbar',

  setup() {
    const { rootElement } = useRootElement();
    const {
      clients,
      getAllTools,
    } = useInline();

    const allTools = computed(() => getAllTools());

    const selectionRect: Ref<DOMRect|null>= ref(null);
    const updateSelectionRect = () => {
      const selection = getSelection();
      if (!selection) {
        console.warn('Could not get selection');
        return;
      }
      selectionRect.value = getRect(selection);
    };

    const showing: Ref<boolean> = ref(false);

    const show = () => {
      showing.value = true;
      updateSelectionRect();
    };
    const hide = () => { showing.value = false; };

    const style = computed(() => {
      const rootRect = rootElement.value?.getBoundingClientRect();
      const x = (selectionRect.value?.x || 0)
              - (rootRect?.left || 0);
      const y = (selectionRect.value?.y || 0)
              + (selectionRect.value?.height || 0)
              - (rootRect?.top || 0);
      return {
        left: Math.floor(x) + 'px',
        top: Math.floor(y) + 'px',
      };
    });

    const classes = computed(() => ({
      'sb-inline-toolbar': true,
      'sb-inline-toolbar_hidden': !showing.value,
    }));

    const onSelectionChanged = debounce(() => {
      const selection = getSelection();
      if (!selection) {
        console.warn('Could not get selection');
        return
      }

      const range = getRangeFromSelection(selection);
      // If we're not selecting anything, bail
      if (!range || range.endOffset === range.startOffset) {
        hide();
        return;
      }

      const focusedElement = getAnchorElementForSelection(selection);
      if (!focusedElement) {
        hide();
        return;
      }

      // If new selection is not in registered clients, close it
      if (!clients.value.find(client => client === focusedElement)) {
        hide();
        return;
      }

      show();
    }, 50);

    onMounted(() => {
      rootElement.value?.addEventListener('click', close);
      document.addEventListener('selectionchange', onSelectionChanged, true);
    });

    onBeforeUnmount(() => {
      rootElement.value?.removeEventListener('click', close);
      document.removeEventListener('selectionchange', onSelectionChanged);
    });

    return () => allTools.value.length
      ? <div
        style={style.value}
        class={classes.value}
      >{allTools.value.map(tool => tool.ui)}</div>
      : null;
  },
});
