<template>
  <div
    ref="rail"
    class="action-rail d-flex"
  >
    <template v-for="(action, index) of visible">
      <div class="visible-item">
        <slot
          name="visible"
          :action="action"
          :index="index"
        ></slot>
      </div>
    </template>
    <v-menu
      v-if="showMenu"
      v-bind="menuProps"
      v-on="menuOn"
    >
      <template #activator="{ props }">
        <v-btn v-bind="mergeProps(props, menuActivatorProps)" />
      </template>
      <v-list>
        <template v-for="(action, index) of hidden">
          <div class="hidden-item">
            <slot
              name="hidden"
              :action="action"
              :index="index"
            ></slot>
          </div>
        </template>
      </v-list>
    </v-menu>
  </div>
</template>

<script setup lang="ts">
import { computed, mergeProps, onBeforeUnmount, onMounted, ref } from 'vue';

type Action<T = Record<string, unknown>> = {
  width: number;
  props: Record<string, any>;
} & T;

interface Props {
  actions?: Action[];
  menuProps?: Record<string, unknown>;
  menuOn?: Record<string, unknown>;
  menuActivatorProps?: Record<string, unknown>;
}

const props = withDefaults(defineProps<Props>(), {
  actions: () => [],
  menuProps: () => ({}),
  menuOn: () => ({}),
  menuActivatorProps: () => ({}),
});

const rail = ref<HTMLDivElement>();
const splitIndex = ref<number>(0);

/* v8 ignore start -- @preserve */
const observer = new ResizeObserver((entries) => {
  if (entries.length > 0) {
    const railWidth = entries[0].contentRect.width;
    calculateSplitIndex(railWidth);
  }
});
/* v8 ignore stop -- @preserve */

const visible = computed(() => {
  return props.actions.slice(0, splitIndex.value);
});

const hidden = computed(() => {
  return props.actions.slice(splitIndex.value);
});

const showMenu = computed(() => {
  return hidden.value.length > 0;
});

onMounted(() => {
  observer.observe(rail.value!);
  const rect = rail.value!.getBoundingClientRect();
  calculateSplitIndex(rect.width);
});

onBeforeUnmount(() => {
  observer.disconnect();
});

/* v8 ignore start -- @preserve */
function calculateSplitIndex(railWidth: number): void {
  const widths = props.actions.map((action) => action.width);
  let sum = 48;
  for (const [idx, width] of widths.entries()) {
    if (sum + width < railWidth) {
      sum += width;
      splitIndex.value = idx + 1;
    }
  }
}
/* v8 ignore stop -- @preserve */
</script>

<style lang="scss">
.action-rail {
  min-width: 0;
}
</style>
