import { Build } from "./utils";

declare global {
  interface Generator<T = unknown, TReturn = any, TNext = unknown> {
    /**
     * Returns the element at a specified index in a sequence.
     * @param index The zero-based index of the element to retrieve.
     * @returns The element at the specified position in the source sequence.
     */
    at(index: number): T;
    /**
     * Returns the element at a specified index in a sequence or a default value if the index is out of range.
     * @param index The zero-based index of the element to retrieve.
     * @param allow_empty Signify to return undefined if there is no item at that index.
     * @returns Undefined if the index is outside the bounds of the source sequence; otherwise, the element at the specified position in the source sequence.
     */
    at(index: number, allow_empty: "or-default"): T | undefined;
  }

  interface AsyncGenerator<T = unknown, TReturn = any, TNext = unknown> {
    /**
     * Returns the element at a specified index in a sequence.
     * @param index The zero-based index of the element to retrieve.
     * @returns The element at the specified position in the source sequence.
     */
    at(index: number): Promise<T>;
    /**
     * Returns the element at a specified index in a sequence or a default value if the index is out of range.
     * @param index The zero-based index of the element to retrieve.
     * @param allow_empty Signify to return undefined if there is no item at that index.
     * @returns Undefined if the index is outside the bounds of the source sequence; otherwise, the element at the specified position in the source sequence.
     */
    at(index: number, allow_empty: "or-default"): Promise<T | undefined>;
  }
}

Build(
  "at",
  function (index, allow_empty) {
    let i = 0;
    for (const item of this) {
      if (i === index) {
        return item;
      }

      i++;
    }

    if (allow_empty) {
      return undefined;
    }

    throw new Error(`Index ${index} does not exist in sequence.`);
  },
  async function (index, allow_empty) {
    let i = 0;
    for await (const item of this) {
      if (i === index) {
        return item;
      }

      i++;
    }

    if (allow_empty) {
      return undefined;
    }

    throw new Error(`Index ${index} does not exist in sequence.`);
  }
);
