import { Assert, IsArray, IsNumber } from "@paulpopat/safe-type";
import { Build, Promised } from "./utils";

declare global {
  interface Generator<T = unknown, TReturn = any, TNext = unknown> {
    sum(this: Generator<number, TReturn, TNext>): number;
    sum(selector: (item: T) => number): number;
  }

  interface AsyncGenerator<T = unknown, TReturn = any, TNext = unknown> {
    sum(this: AsyncGenerator<number, TReturn, TNext>): number;
    sum(selector: (item: T) => Promised<number>): Promise<number>;
  }
}

function GetSum(items: number[]) {
  Assert(IsArray(IsNumber), items);
  return items.reduce((c, n) => c + n, 0);
}

Build(
  "sum",
  function (selector) {
    let sel = selector ?? ((i) => i);
    const data = [];
    for (const item of this) {
      data.push(sel(item));
    }

    return GetSum(data);
  },
  async function (selector) {
    let sel = selector ?? ((i) => i);
    const data = [];
    for await (const item of this) {
      data.push(await Promise.resolve(sel(item)));
    }

    return GetSum(data);
  }
);
