import type {
  FlattenDataNode,
  InternalDataEntity,
  Key,
  LegacyDataNode,
  RawValueType,
} from './interface';
import type { SkipType } from './hooks/useKeyValueMapping';
import type { ComputedRef, InjectionKey, PropType } from 'vue';
import { computed, defineComponent, inject, provide } from 'vue';

interface ContextProps {
  checkable: boolean;
  customCheckable: () => any;
  checkedKeys: Key[];
  halfCheckedKeys: Key[];
  treeExpandedKeys: Key[];
  treeDefaultExpandedKeys: Key[];
  onTreeExpand: (keys: Key[]) => void;
  treeDefaultExpandAll: boolean;
  treeIcon: any;
  showTreeIcon: boolean;
  switcherIcon: any;
  treeLine: boolean;
  treeNodeFilterProp: string;
  treeLoadedKeys: Key[];
  treeMotion: any;
  loadData: (treeNode: LegacyDataNode) => Promise<unknown>;
  onTreeLoad: (loadedKeys: Key[]) => void;

  // Cache help content. These can be generated by parent component.
  // Let's reuse this.
  getEntityByKey: (key: Key, skipType?: SkipType, ignoreDisabledCheck?: boolean) => FlattenDataNode;
  getEntityByValue: (
    value: RawValueType,
    skipType?: SkipType,
    ignoreDisabledCheck?: boolean,
  ) => FlattenDataNode;

  slots: {
    title?: (data: InternalDataEntity) => any;
    titleRender?: (data: InternalDataEntity) => any;
    [key: string]: (d: any) => any | undefined;
  };
}

const SelectContextKey: InjectionKey<ComputedRef<ContextProps>> = Symbol('SelectContextKey');

export const SelectContext = defineComponent({
  name: 'SelectContext',
  props: {
    value: { type: Object as PropType<ContextProps> },
  },
  setup(props, { slots }) {
    provide(
      SelectContextKey,
      computed(() => props.value),
    );
    return () => slots.default?.();
  },
});

export const useInjectTreeSelectContext = () => {
  return inject(
    SelectContextKey,
    computed(() => ({} as ContextProps)),
  );
};