export default class FakerUtils {
    private static NUMBERS = '0123456789';
    private static UPPERCASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    private static LOWERCASE = 'abcdefghijklmnopqrstuvwxyz';
    private static ALPHABET = FakerUtils.UPPERCASE + FakerUtils.LOWERCASE;
    private static ALPHANUMERIC = FakerUtils.NUMBERS + FakerUtils.ALPHABET;

    private static generateRandomString(length: number, characters: string): string {        
        return Array.from(crypto.getRandomValues(new Uint8Array(length)))
            .map(byte => characters[byte % characters.length])
            .join('');
    }

    public static generateRandomNumber(min: number, max: number): number {
        const range = max - min + 1;
        const bytesNeeded = Math.ceil(Math.log2(range) / 8);
        const randomBytes = new Uint8Array(bytesNeeded);
        crypto.getRandomValues(randomBytes);
        const randomValue = randomBytes.reduce((acc, byte) => (acc << 8) + byte, 0);
        return min + (randomValue % range);
    }

    public static getRandomTestID(): string {
        return FakerUtils.generateRandomString(8, FakerUtils.ALPHANUMERIC);
    }

    public static getRandomProperty(obj: Record<string, any>): string {
        const keys = Object.keys(obj);
        const randomIndex = FakerUtils.generateRandomNumber(0, keys.length - 1);
        return keys[randomIndex];
    }

    public static getRandomTail(registrationPrefix: string = "XX", testID: string = ""): string {
        return FakerUtils.formatString(FakerUtils.generateRandomString(8, FakerUtils.ALPHANUMERIC));
    }

    public static getRandomEmail(domainSuffix: string = "@test.com", testID: string = ""): string {
        const retval = FakerUtils.formatString("{0}{1}", FakerUtils.generateRandomString(8, FakerUtils.ALPHANUMERIC), domainSuffix);
        return retval;
    }

    public static getRandomLastName(testID: string = " - "): string {
        return FakerUtils.formatString(" - {0}", FakerUtils.generateRandomString(21, FakerUtils.ALPHABET));
    }

    public static getObjectName(prefix: string, testID: string = ""): string {
        return FakerUtils.formatString("{0} - {1}", prefix, FakerUtils.generateRandomString(21, FakerUtils.ALPHANUMERIC));
    }

    private static formatString(template: string, ...args: (string | (() => string))[]): string {
        return template.replace(/\{(\d+)\}/g, (match, index) => {
            const arg = args[parseInt(index)];
            return typeof arg === 'function' ? arg() : arg || '';
        });
    }
}