// import Config from '@ioc:Adonis/Core/Config';
// import config from '@adonisjs/core/services/config'
import env from '#start/env';
import User from '#models/user';
import { generateSecret, verifyToken } from 'node-2fa/dist/index.js';
// import cryptoRandomString from 'crypto-random-string';
import QRCode from 'qrcode';
import crypto from 'crypto';
import { TotpState } from '#contracts/enums';

// npm install node-2fa --save
// npm install crypto-random-string --save
// import { cryptoRandomStringAsync } from 'crypto-random-string/index';
// npm install qrcode --save
// npm i --save-dev @types/qrcode

class TwoFactorAuthProvider {
    private issuer: string = env.get('APP_NAME') || 'TethysCloud';

    /**
     * generateSecret will generate a user-specific 32-character secret.
     * We’re providing the name of the app and the user’s email as parameters for the function.
     * This secret key will be used to verify whether the token provided by the user during authentication is valid or not.
     *
     * Return the default global focus trap stack     *
     * @param {User} user user for the secrect
     * @return {string}
     */
    public generateSecret(user: User) {
        const secret = generateSecret({
            name: this.issuer,
            account: user.email,
        });
        return secret.secret;
    }

    /**
     * We also generated recovery codes which can be used in case we’re unable to retrieve tokens from 2FA applications.
     * We assign the user a list of recovery codes and each code can be used only once during the authentication process.
     *   The recovery codes are random strings generated using the cryptoRandomString library.
     *
     * Return recovery codes
     * @return {string[]}
     */
    public generateRecoveryCodes(): string[] {
        const recoveryCodeLimit: number = 8;
        const codes: string[] = [];
        for (let i = 0; i < recoveryCodeLimit; i++) {
            const recoveryCode: string = `${this.secureRandomString()}-${this.secureRandomString()}`;
            codes.push(recoveryCode);
        }
        return codes;
    }

    private secureRandomString() {
        // return await cryptoRandomString.async({ length: 10, type: 'hex' });
        return this.generateRandomString(10, 'hex');
    }

    private generateRandomString(length: number, type: 'hex' | 'base64' | 'numeric' = 'hex'): string {
        const byteLength = Math.ceil(length * 0.5); // For hex encoding, each byte generates 2 characters
        const randomBytes = crypto.randomBytes(byteLength);

        switch (type) {
            case 'hex':
                return randomBytes.toString('hex').slice(0, length);
            case 'base64':
                return randomBytes.toString('base64').slice(0, length);
            case 'numeric':
                return randomBytes
                    .toString('hex')
                    .replace(/[a-fA-F]/g, '') // Remove non-numeric characters
                    .slice(0, length);
            default:
                throw new Error('Invalid type specified');
        }
    }

    // public async generateQrCode(user: User) : Promise<{svg: string; url: string; secret: string; }> {
    //     const issuer = encodeURIComponent(this.issuer); // 'TethysCloud'
    //     // const userName = encodeURIComponent(user.email); // 'rrqx9472%40tethys.at'
    //     const label = `${this.issuer}:${user.email}`;

    //     const algorithm = encodeURIComponent("SHA256");
    //     const query = `?secret=${user.twoFactorSecret}&issuer=${issuer}&algorithm=${algorithm}&digits=6`; // '?secret=FEYCLOSO627CB7SMLX6QQ7BP75L7SJ54&issuer=TethysCloud'
    //     const url = `otpauth://totp/${label}${query}`; // 'otpauth://totp/rrqx9472%40tethys.at?secret=FEYCLOSO627CB7SMLX6QQ7BP75L7SJ54&issuer=TethysCloud'
    //     const svg = await QRCode.toDataURL(url);
    //     const secret = user.twoFactorSecret as string;
    //     return { svg, url, secret };
    // }

    public async generateQrCode(user: User, twoFactorSecret?: string): Promise<{ svg: string; url: string; secret: string }> {
        const issuer = encodeURIComponent(this.issuer); // 'TethysCloud'
        // const userName = encodeURIComponent(user.email); // 'rrqx9472%40tethys.at'
        const label = `${this.issuer}:${user.email}`;

        // const algorithm = encodeURIComponent('SHA256');
        const secret = twoFactorSecret ? twoFactorSecret : (user.twoFactorSecret as string);
        const query = `?secret=${secret}&issuer=${issuer}&digits=6`; // '?secret=FEYCLOSO627CB7SMLX6QQ7BP75L7SJ54&issuer=TethysCloud'

        const url = `otpauth://totp/${label}${query}`; // 'otpauth://totp/rrqx9472%40tethys.at?secret=FEYCLOSO627CB7SMLX6QQ7BP75L7SJ54&issuer=TethysCloud'
        const svg = await QRCode.toDataURL(url);

        return { svg, url, secret };
    }

    public async enable(user: User, token: string): Promise<boolean> {
        const isValid = verifyToken(user.twoFactorSecret as string, token, 1);
        if (!isValid) {
            return false;
        }
        user.state = TotpState.STATE_ENABLED;
        if (await user.save()) {
            return true;
        }
        return false;
    }

    public async validate(user: User, token: string): Promise<boolean> {
        const isValid = verifyToken(user.twoFactorSecret as string, token, 1);
        if (isValid) {
            return true;
        }
        return false;
    }
}

export default new TwoFactorAuthProvider();
