import { Build, Promised } from "./utils";

declare global {
  interface Generator<T = unknown, TReturn = any, TNext = unknown> {
    /**
     * Determines whether all elements of a sequence satisfy a condition.
     * @param predicate A function to test each element for a condition.
     * @returns true if every element of the source sequence passes the test in the specified predicate, or if the sequence is empty; otherwise, false.
     */
    all(predicate: (item: T) => boolean): boolean;
    /**
     * Determines whether all elements of a sequence satisfy a condition.
     * @param predicate A function to test each element for a condition.
     * @returns A type inferences boolean to determine the type of the generator.
     */
    all<TTest extends T>(
      predicate: (item: T) => item is TTest
    ): this is Generator<TTest, TReturn, TNext>;
  }

  interface AsyncGenerator<T = unknown, TReturn = any, TNext = unknown> {
    /**
     * Determines whether all elements of a sequence satisfy a condition.
     * @param predicate A function to test each element for a condition.
     * @returns true if every element of the source sequence passes the test in the specified predicate, or if the sequence is empty; otherwise, false.
     */
    all(predicate: (item: T) => Promised<boolean>): Promise<boolean>;
  }
}

Build(
  "all",
  function (predicate) {
    for (const item of this) {
      if (!predicate(item)) return false;
    }

    return true;
  },
  async function (predicate) {
    for await (const item of this) {
      if (!(await Promise.resolve(predicate(item)))) return false;
    }

    return true;
  }
);
