import { toArray } from '../types/Array';
import { ErrorOrigin } from '../types/ErrorOrigin';
import { List, toList } from '../types/List';
import { asString } from '../types/Text';
import { on, use } from '../types/Constructor';
import { keys, values } from '../types/Object';
type Pro = A | PromiseLike;
type Aw = Awaited;
export const resolve = (subject: S | PromiseLike): Promise => Promise.resolve(subject);
export const reject = (e: ErrorOrigin): Promise => Promise.reject(e);
export const tuple = {
2: (first: Pro, second: Pro): Promise<[Aw, Aw]> => Promise.all([first, second]),
3: (first: Pro, second: Pro, third: Pro): Promise<[Aw, Aw, Aw]> => Promise.all([first, second, third]),
4: (first: Pro, second: Pro, third: Pro, forth: Pro): Promise<[Aw, Aw, Aw, Aw]> =>
Promise.all([first, second, third, forth]),
5: (first: Pro, second: Pro, third: Pro, forth: Pro, fifth: Pro): Promise<[Aw, Aw, Aw, Aw, Aw]> =>
Promise.all([first, second, third, forth, fifth]),
all: (first: Pro, second: Pro[]): Promise<[Aw, Aw]> => Promise.all([first, Promise.all(second)]),
spread: (first: Pro, ...second: Pro[]): Promise<[Aw, Aw]> => Promise.all([first, Promise.all(toArray(second))]),
list: (list: Pro[]): Promise>> => Promise.all([...list]).then(toList),
settled: (list: Pro[]): Promise<{ fulfilled: List>; rejected: List }> =>
Promise.allSettled([...list]).then(rs => ({
fulfilled: toList(...rs.filter(r => r.status === 'fulfilled').map(r => r.value)),
rejected: toList(...rs.filter(r => r.status === 'rejected').map(r => asString(r.reason))),
})),
object: >(obj: T): Promise<{ [K in keyof T]: Aw }> =>
use(keys(obj), ks => tuple.list(values(obj)).then(vs => vs.reduce((acc: any, v, i) => on(acc, a => (a[ks[i]] = v)), {}) as { [K in keyof T]: Aw })),
};
export const tuple2 = tuple[2];
export const tuple3 = tuple[3];
export const tuple4 = tuple[4];
export const tuple5 = tuple[5];
export const tupleO = tuple.object;
export const settled = tuple.settled;