import {
  computed,
  getCurrentInstance,
  inject,
  onBeforeUnmount,
  onMounted,
  provide,
  ref,
  toRef
} from "vue";
import { deepEqual, getUid, propsFactory, wrapInArray } from "@veno-ui/utils";
import { consoleWarn, findChildren } from "../../utils";
import { useProxiedModel } from "../proxied-model";
const makeGroupProps = propsFactory({
  /**
   * @zh 选择的值
   */
  modelValue: {
    type: [Number, Boolean, String, Array, Object],
    default: void 0
  },
  /**
   * @zh 支持多选
   */
  multiple: Boolean,
  /**
   * @zh 是否强制选择
   */
  mandatory: [Boolean, String],
  /**
   * @zh 最大值
   */
  max: Number,
  /**
   * @zh 选中后的 class
   */
  selectedClass: String,
  /**
   * @zh 是否禁用
   */
  disabled: Boolean
}, "group");
const makeGroupItemProps = propsFactory({
  /**
   * @zh 选中后的值
   */
  value: null,
  /**
   * @zh 是否禁用
   */
  disabled: Boolean,
  /**
   * @zh 选中后的 class
   */
  selectedClass: String
}, "group-item");
function useGroupItem(props, injectKey, required = true) {
  const vm = getCurrentInstance();
  if (!vm) {
    throw new Error(
      "[VenoUi] useGroupItem composable must be used inside a component setup function"
    );
  }
  const group = inject(injectKey, null);
  if (!group) {
    if (!required)
      return group;
    throw new Error(`[VenoUi] Could not find useGroup injection with symbol ${injectKey.description}`);
  }
  const id = `ve-group-item-${getUid()}`;
  const value = toRef(props, "value");
  const disabled = computed(() => group.disabled.value || props.disabled);
  group.register({
    id,
    value,
    disabled
  }, vm);
  onBeforeUnmount(() => group.unregister(id));
  const isSelected = computed(() => group.isSelected(id));
  const selectedClass = computed(() => isSelected.value && (group.selectedClass.value ?? props.selectedClass));
  return {
    id,
    isSelected,
    toggle: () => group.select(id, !isSelected.value),
    select: (value2) => group.select(id, value2),
    selectedClass,
    value,
    disabled,
    group
  };
}
function useGroup(props, injectKey) {
  let isUnmounted = false;
  const items = ref([]);
  const selected = useProxiedModel(
    props,
    "modelValue",
    [],
    (v) => {
      if (v == null)
        return [];
      return getIds(items.value, wrapInArray(v));
    },
    (v) => {
      const arr = getValues(items.value, v);
      return props.multiple ? arr : arr[0];
    }
  );
  const groupVm = getCurrentInstance();
  function register(item, vm) {
    const unwrapped = item;
    const index = findChildren(groupVm?.vnode).slice(1).filter((cmp) => !!cmp.provides[injectKey]).indexOf(vm);
    if (index > -1)
      items.value.splice(index, 0, unwrapped);
    else
      items.value.push(unwrapped);
  }
  function unregister(id) {
    if (isUnmounted)
      return;
    selected.value = selected.value.filter((v) => v !== id);
    forceMandatoryValue();
    const index = items.value.findIndex((item) => item.id === id);
    items.value.splice(index, 1);
  }
  function forceMandatoryValue() {
    const item = items.value.find((item2) => !item2.disabled);
    if (item && props.mandatory === "force" && !selected.value.length) {
      selected.value = [item.id];
    }
  }
  onMounted(() => {
    forceMandatoryValue();
  });
  onBeforeUnmount(() => {
    isUnmounted = true;
  });
  function select(id, isSelected) {
    const item = items.value.find((item2) => item2.id === id);
    if (isSelected && item?.disabled)
      return;
    if (props.multiple) {
      const internalValue = selected.value.slice();
      const index = internalValue.findIndex((v) => v === id);
      if (props.mandatory && index > -1 && internalValue.length <= 1)
        return;
      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 step(offset) {
    if (props.multiple)
      consoleWarn('This method is not supported when using "multiple" prop');
    if (!selected.value.length) {
      const item = items.value.find((item2) => !item2.disabled);
      item && (selected.value = [item.id]);
    } else {
      const currentId = selected.value[0];
      const currentIndex = items.value.findIndex((i) => i.id === currentId);
      let newIndex = (currentIndex + offset) % items.value.length;
      let newItem = items.value[newIndex];
      while (newItem.disabled && newIndex !== currentIndex) {
        newIndex = (newIndex + offset) % items.value.length;
        newItem = items.value[newIndex];
      }
      if (newItem.disabled)
        return;
      selected.value = [items.value[newIndex].id];
    }
  }
  const state = {
    vm: groupVm,
    register,
    unregister,
    selected,
    select,
    disabled: toRef(props, "disabled"),
    prev: () => step(items.value.length - 1),
    next: () => step(1),
    isSelected: (id) => selected.value.includes(id),
    selectedClass: computed(() => props.selectedClass),
    items
  };
  provide(injectKey, state);
  return state;
}
function getIds(items, modelValue) {
  const ids = [];
  for (const item of items) {
    if (item.value != null) {
      if (modelValue.find((value) => deepEqual(value, item.value)) != null) {
        ids.push(item.id);
      }
    } else if (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;
}
export {
  makeGroupItemProps,
  makeGroupProps,
  useGroup,
  useGroupItem
};
//# sourceMappingURL=index.mjs.map
