import { Collector, Supplier } from '../collector';
import { toArray } from './toArray';
import { GroupingByCollector } from './groupingBy';
import { flatMapping } from '../transformers/flatMapping';
import { mapping } from '../transformers/mapping';

export function groupingByMany<T, K> ( mapper : ( item : T ) => Iterable<K> ) : Collector<T, Map<K, T[]>, Map<K, T[]>>;
export function groupingByMany<T, K, A, D> ( mapper : ( item : T ) => Iterable<K>, collector : Collector<T, A, D> ) : Collector<T, Map<K, A>, Map<K, D>>;
export function groupingByMany<T, K, A, D, M extends Map<K, D>> ( mapper : ( item : T ) => Iterable<K>, supplier : Supplier<M>, collector : Collector<T, A, D> ) : Collector<T, Map<K, A>, Map<K, D>>;
export function groupingByMany<T, K, A, D, M extends Map<K, D>> ( mapper : ( item : T ) => Iterable<K>, supplier ?: Supplier<M> | Collector<T, A, D>, collector ?: Collector<T, A, D> ) : Collector<T, any, any> {
    if ( !supplier && !collector ) {
        return groupingByMany( mapper, () => new Map(), toArray() );
    } else if ( !collector ) {
        return groupingByMany( mapper, () => new Map(), supplier as Collector<T, A, D> );
    }

    return flatMapping<T, [K, T], any, any>( 
        item => Array.from( mapper( item ) ).map( k => [ k, item ] as [ K, T ] ), 
        new GroupingByCollector<[K, T], K, any, any, any>( 
            pair => pair[ 0 ],
            supplier as Supplier<M>, 
            mapping( pair => pair[ 1 ] )
        ) 
    );
}
