// Utilities
import { computed, inject, onBeforeUnmount, onMounted, provide, reactive, toRef } from 'vue';
import { useProxiedModel } from "./proxiedModel.mjs";
import { consoleWarn, deepEqual, getUid, wrapInArray } from "../util/index.mjs"; // Types

// Composables
export function useGroupItem(props, injectKey) {
  const group = inject(injectKey, null);

  if (!group) {
    throw new Error("[Vuetify] Could not find useGroup injection with symbol ".concat(injectKey.description));
  }

  const id = getUid();
  group.register({
    id,
    value: toRef(props, 'value'),
    disabled: toRef(props, 'disabled')
  }, props.index);
  onBeforeUnmount(() => {
    group.unregister(id);
  });
  const isSelected = computed(() => {
    return group.isSelected(id);
  });
  return {
    isSelected,
    toggle: () => group.select(id, !isSelected.value),
    select: value => group.select(id, value)
  };
}
export function useGroup(props, injectKey) {
  const items = reactive([]);
  const selected = useProxiedModel(props, 'modelValue', [], v => {
    if (v == null) return [];
    return getIds(items, wrapInArray(v));
  }, v => {
    const arr = getValues(items, v);
    return props.multiple ? arr : arr[0];
  });

  function register(item, index) {
    // Is there a better way to fix this typing?
    const unwrapped = item;
    if (index != null) items.splice(index, 0, unwrapped);else items.push(unwrapped);
  }

  function unregister(id) {
    selected.value = selected.value.filter(v => v !== id);

    if (props.mandatory && !selected.value.length) {
      selected.value = [items[items.length - 1].id];
    }

    const index = items.findIndex(item => item.id === id);
    items.splice(index, 1);
  }

  onMounted(() => {
    // If mandatory and nothing is selected, then select first non-disabled item
    const item = items.find(item => !item.disabled);

    if (item && props.mandatory && !selected.value.length) {
      selected.value = [item.id];
    }
  });

  function select(id, isSelected) {
    const item = items.find(item => item.id === id);
    if (isSelected && (item == null ? void 0 : item.disabled)) return;

    if (props.multiple) {
      const internalValue = selected.value.slice();
      const index = internalValue.findIndex(v => v === id); // We can't remove value if group is
      // mandatory, value already exists,
      // and it is the only value

      if (props.mandatory && index > -1 && internalValue.length <= 1) return; // We can't add value if it would
      // cause max limit to be exceeded

      if (props.max != null && index < 0 && internalValue.length + 1 > props.max) return;
      if (index < 0 && isSelected) internalValue.push(id);else if (index >= 0 && !isSelected) internalValue.splice(index, 1);
      selected.value = internalValue;
    } else {
      if (props.mandatory && selected.value.includes(id)) return;
      selected.value = isSelected ? [id] : [];
    }
  }

  function getOffsetId(offset) {
    // getting an offset from selected value obviously won't work with multiple values
    if (props.multiple) consoleWarn('This method is not supported when using "multiple" prop'); // If there is nothing selected, then next value is first item

    if (!selected.value.length) return items[0].id;
    const currentId = selected.value[0];
    const currentIndex = items.findIndex(i => i.id === currentId);
    const newIndex = (currentIndex + offset) % items.length;
    return items[newIndex].id;
  }

  const state = {
    register,
    unregister,
    selected,
    select,
    prev: () => selected.value = [getOffsetId(items.length - 1)],
    next: () => selected.value = [getOffsetId(1)],
    step: steps => selected.value = [getOffsetId(steps)],
    isSelected: id => selected.value.includes(id)
  };
  provide(injectKey, state);
  return state;
}

function getIds(items, modelValue) {
  const ids = [];

  for (const item of items) {
    if (item.value != null && modelValue.find(value => deepEqual(value, item.value)) || modelValue.includes(item.id)) {
      ids.push(item.id);
    }
  }

  return ids;
}

function getValues(items, ids) {
  const values = [];

  for (const item of items) {
    if (ids.includes(item.id)) {
      values.push(item.value != null ? item.value : item.id);
    }
  }

  return values;
}
//# sourceMappingURL=group.mjs.map