import { markRaw, type Ref, ref, watch } from 'vue';
import { arrayIncludes } from './array';
export const timeout = (delay: number = 0) =>
  new Promise<void>((resolve) => setTimeout(resolve, delay));

export function useRefresh() {
  const key = ref(0);
  return {
    key,
    refresh: () => ++key.value,
  };
}

export function* chainIterables<T>(iterables: Iterable<T>[]): Generator<T, void, undefined> {
  for (const iterable of iterables) {
    yield* iterable;
  }
}
export class IDPool {
  protected _maxID: number;
  protected _unUsedIDSet: Set<number>;

  constructor(start: number = 0) {
    this._maxID = start;
    this._usedIDSet = new Set<number>();
    this._unUsedIDSet = new Set<number>();
    return markRaw(this);
  }
  protected _usedIDSet: Set<number>;

  get usedIDSet(): ReadonlySet<number> {
    return this._usedIDSet;
  }

  newID(...idToRemove: number[]) {
    let id: number;
    if (this._unUsedIDSet.size) {
      [id] = this._unUsedIDSet;
      this._unUsedIDSet.delete(id);
    } else {
      id = this._maxID++;
    }
    this._usedIDSet.add(id);
    this.removeID(...idToRemove);
    return id;
  }

  removeID(...allID: number[]) {
    for (const id of allID) {
      if (!this._usedIDSet.delete(id)) {
        return;
      }
      this._unUsedIDSet.add(id);
    }
  }

  reset() {
    this._maxID = 0;
    this._unUsedIDSet.clear();
    this._usedIDSet.clear();
  }
}

export function waitRef<T>(ref: Ref<T>): Promise<void>;
export function waitRef<T, const R extends T>(ref: Ref<T>, ...expect: R[]): Promise<R>;
export function waitRef<T, const R extends T>(ref: Ref<T>, ...expect: R[]) {
  return new Promise<R | void>((resolve) => {
    const unWatch = watch(ref, (value) => {
      if (!expect.length) {
        unWatch();
        resolve();
      } else if (arrayIncludes(expect, value)) {
        unWatch();
        resolve(value);
      }
    });
  });
}

/**
 * 检测key是否为obj的键，并收紧key的类型.
 */
export const isKeyOf = <T extends object>(obj: T, key: keyof any): key is keyof typeof obj =>
  key in obj;
