import Base64 from './base64';

export async function sha256(string: string): Promise<string> {
    const utf8 = new TextEncoder().encode(string);
    const hashBuffer = await crypto.subtle.digest('SHA-256', utf8);
    return Base64.encode(hashBuffer);
}

export function getRandomUUID() {
    return crypto.randomUUID();
}

export async function getObjectId(object: any) {
    return await await sha256(JSON.stringify(object));
}

/**
 * returns a random list of elements of the array. It is possible that elements from the provided array will be repeated.
 * @param arr an array 
 * @param elementCount the number of elements returned
 * @returns an array array the size of elementCount with random elements from arr. Elements might be repeated!
 */
export function getRandomElements(arr: any[], elementCount: number): any[] {
    if (arr.length < 2) {
        throw new Error('array too small! Selection will be deterministic!');
    }
    const result: any[] = [];
    const randomIndexes = new Uint32Array(elementCount);
    crypto.getRandomValues(randomIndexes);
    for (let i = 0; i < randomIndexes.length; i++) {
        result.push(arr[randomIndexes[i] % arr.length]);
    }
    return result;
}

/**
 * returns a random set of elements of the array. It is not possible that elements from the provided array will be repeated.
 * @param arr an array 
 * @param elementCount the number of elements returned that must be smaller than the elementCound.
 * @returns an array array the size of elementCount with random elements from arr. Elements won't be repeated!
 */
export function getRandomSet<T>(arr: T[], elementCount: number): T[] {
    if (elementCount > arr.length) {
        throw new Error('not enough elements in array to draw random subset!');
    }
    const result: T[] = [];
    const randomIndexes = new Uint32Array(elementCount);
    crypto.getRandomValues(randomIndexes);
    for (let i = 0; i < randomIndexes.length; i++) {
        result.push(...arr.splice(randomIndexes[i] % arr.length, 1));
    }
    return result;
}

export async function getTimeBasedAddress(address: string) {
    const todayMidnightUTC = new Date();
    todayMidnightUTC.setUTCHours(0, 0, 0, 0);
    const todayMidnightUTCTimestamp = todayMidnightUTC.getTime();
    const timeBasedAddress = await sha256(address + todayMidnightUTCTimestamp);
    return timeBasedAddress;
}

export async function getRandomNumber(max: number, min = 0): Promise<number> {
    const randomBuffer = new Uint32Array(1);
    crypto.getRandomValues(randomBuffer);
    return randomBuffer[0] % (max - min) + min;
}