/**
 * @module secret helper/util/etc. functions
 *
 * this is where you will find helper functions like those that generate
 * and parse ibs for secret.
 */
// import * as pathUtils from 'path';
// import { statSync } from 'node:fs';
// import { readFile, } from 'node:fs/promises';
// import * as readline from 'node:readline/promises';
// import { stdin, stdout } from 'node:process'; // decide if use this or not
import { extractErrorMsg, } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
import { CLASSNAME_REGEXP, } from '@ibgib/helper-gib/dist/constants.mjs';
import { validateIbGibIntrinsically } from '@ibgib/ts-gib/dist/V1/validate-helper.mjs';
import { Factory_V1 } from "@ibgib/ts-gib/dist/V1/factory.mjs";
import { GLOBAL_LOG_A_LOT } from "../../core-constants.mjs";
import { SecretType, VALID_SECRET_TYPES, } from './secret-types.mjs';
import { SECRET_ATOM, SECRET_NAME_REGEXP, SECRET_REL8N_NAME, } from './secret-constants.mjs';
import { INVALID_DATE_STRING } from '../other/other-constants.mjs';
import { hash16816 } from '../other/ibgib-helper.mjs';
/**
 * for verbose logging
 */
const logalot = GLOBAL_LOG_A_LOT;
export function validateCommonSecretData({ data, }) {
    const lc = `[${validateCommonSecretData.name}]`;
    try {
        if (logalot) {
            console.log(`${lc} starting...`);
        }
        if (!data) {
            throw new Error(`data required (E: f7d9a12390e2d3821c07c115a289b5af)`);
        }
        const errors = [];
        const { name, /*uuid,*/ classname, expirationUTC, type, } = data;
        if (name) {
            if (!name.match(SECRET_NAME_REGEXP)) {
                errors.push(`name must match regexp: ${SECRET_NAME_REGEXP} (E: 27023cc5e5afb456e4b8ebfd1e653de6)`);
            }
        }
        else {
            errors.push(`name required. (E: fe088277e7677ad295b5e914ed644ab4)`);
        }
        if (type) {
            if (!VALID_SECRET_TYPES.includes(type)) {
                errors.push(`type (${type}) is invalid. must be one of ${VALID_SECRET_TYPES.join(', ')} (E: 413a1c899dcc4623a38be35bdf144217)`);
            }
        }
        else {
            errors.push(`type required. (E: 6126767cc5fd4c898d432b139652e5d1)`);
        }
        // if (uuid) {
        //     if (!uuid.match(UUID_REGEXP)) {
        //         errors.push(`uuid must match regexp: ${UUID_REGEXP} (E: 1b035a31d191435217010ac272681c82)`);
        //     }
        // } else {
        //     errors.push(`uuid required. (E: 55fee43e758fcf542866bdabe7321633)`);
        // }
        if (classname) {
            if (!classname.match(CLASSNAME_REGEXP)) {
                errors.push(`classname must match regexp: ${CLASSNAME_REGEXP} (E: 301c325035ad3297c2744fd25ec618dd)`);
            }
        }
        if (expirationUTC) {
            let date = new Date(expirationUTC);
            if (date.toString() === INVALID_DATE_STRING) {
                errors.push(`invalid expirationUTC (${expirationUTC}) (E: 969a126f12b742adbf9d671d3fdd782f)`);
            }
        }
        else {
            errors.push(`expirationUTC required (E: f1ff3bcec74946908f0f37f9282e917d)`);
        }
        return errors;
    }
    catch (error) {
        console.error(`${lc} ${extractErrorMsg(error)}`);
        throw error;
    }
    finally {
        if (logalot) {
            console.log(`${lc} complete.`);
        }
    }
}
export async function validateCommonSecretIbGib({ ibGib, }) {
    const lc = `[${validateCommonSecretIbGib.name}]`;
    try {
        if (logalot) {
            console.log(`${lc} starting... (I: 596f5952f6a18ebb23ff270520818eaa)`);
        }
        const intrinsicErrors = await validateIbGibIntrinsically({ ibGib: ibGib }) ?? [];
        if (!ibGib.data) {
            throw new Error(`SecretIbGib.data required (E: df00780071919f55c762ee0756cf46bc)`);
        }
        const ibErrors = [];
        // ib
        let { atom, type, name, } = parseSecretIb({ ib: ibGib.ib });
        if (atom !== SECRET_ATOM) {
            ibErrors.push(`invalid secret atom. must be ${SECRET_ATOM} (E: 56c5874056ff8d07e1875cc38eccf0c3)`);
        }
        if (!type) {
            ibErrors.push(`secret type required (E: 273042f54b363c094b466f85baef3c10)`);
        }
        if (!name) {
            ibErrors.push(`secret name required (E: 670718e47214d0cdfa844d8f7d756477)`);
        }
        // data
        const dataErrors = validateCommonSecretData({ data: ibGib.data });
        let result = [...(intrinsicErrors ?? []), ...(ibErrors ?? []), ...(dataErrors ?? [])];
        if (result.length > 0) {
            return result;
        }
        else {
            return undefined;
        }
    }
    catch (error) {
        console.error(`${lc} ${extractErrorMsg(error)}`);
        throw error;
    }
    finally {
        if (logalot) {
            console.log(`${lc} complete.`);
        }
    }
}
/**
 * builds the ib based on data.
 *
 * atow (02/2024) this is only data.name and data.type.
 *
 * @returns `${SECRET_ATOM} ${type} ${name}` atow (02/2024)
 */
export function getSecretIb({ data, }) {
    const lc = `[${getSecretIb.name}]`;
    try {
        const validationErrors = validateCommonSecretData({ data });
        if (validationErrors.length > 0) {
            throw new Error(`invalid Secret data: ${validationErrors} (E: 07a71e9ba5d574274e2c6a289a3fbabe)`);
        }
        const { name, type } = data;
        return `${SECRET_ATOM} ${type} ${name}`;
    }
    catch (error) {
        console.error(`${lc} ${extractErrorMsg(error)}`);
        throw error;
    }
}
/**
 * Current schema is '[SECRET_ATOM] [type] [name]'
 *
 * NOTE this is space-delimited
 */
export function parseSecretIb({ ib, }) {
    const lc = `[${parseSecretIb.name}]`;
    try {
        if (!ib) {
            throw new Error(`Secret ib required (E: 115e8097c30538526536b240ce4b8e87)`);
        }
        const [atom, type, name] = ib.split(' ');
        if (atom !== SECRET_ATOM) {
            throw new Error(`atom !== ${SECRET_ATOM} (E: 942f3ab95687772a5483ec926ad98124)`);
        }
        if (type !== SecretType.password) {
            console.warn(`${lc} type !== SecretType.password. atow (02/2024) password is the only thing we got. (W: 66511ca217b045629a7816adc4e41fad)`);
        }
        if (!name.match(SECRET_NAME_REGEXP)) {
            throw new Error(`!name.match(SECRET_NAME_REGEXP) (E: 6c95dbb65d3d6d9e0400412bf7ba6824)`);
        }
        return { atom, type, name, };
    }
    catch (error) {
        console.error(`${lc} ${extractErrorMsg(error)}`);
        throw error;
    }
}
export async function createAndRegisterNewSecret({ secretType, secretInfo, metaspace, space, }) {
    const lc = `[${createAndRegisterNewSecret.name}]`;
    try {
        if (logalot) {
            console.log(`${lc} starting... (I: 08a3b2c784ff4689a8abf3ba8f1d7af4)`);
        }
        let resSecretIbGib;
        if (secretType !== SecretType.password) {
            throw new Error(`unknown secretType (${secretType}). only "password" secret type currently implemented. (E: ce3dd7aef4f48f9799f2d37217eed224)`);
        }
        resSecretIbGib = await createAndRegisterNewSecret_password({
            secretType: secretType,
            secretInfo: secretInfo,
            metaspace,
            space,
        });
        return resSecretIbGib;
    }
    catch (error) {
        console.error(`${lc} ${extractErrorMsg(error)}`);
        throw error;
    }
    finally {
        if (logalot) {
            console.log(`${lc} complete.`);
        }
    }
}
async function createAndRegisterNewSecret_password({ secretType, secretInfo, metaspace, space, }) {
    const lc = `[${createAndRegisterNewSecret_password.name}]`;
    try {
        if (logalot) {
            console.log(`${lc} starting... (I: ab330733d4b6bb733f5b5655bcd70a24)`);
        }
        if (secretType !== 'password') {
            throw new Error(`(UNEXPECTED) secretType !== 'password'? (E: b086c3494808a38ad967e55a82364824)`);
        }
        // create the secret ibgib
        const data = {
            ...secretInfo,
        };
        const resFirstGen = await Factory_V1.firstGen({
            ib: getSecretIb({ data }),
            parentIbGib: Factory_V1.primitive({ ib: SECRET_ATOM }),
            data,
            dna: true,
            nCounter: true,
            tjp: { timestamp: true, },
        });
        const secretIbGib = resFirstGen.newIbGib;
        // validate right away before anything else
        const validationErrors = await validateCommonSecretIbGib({ ibGib: secretIbGib }) ?? [];
        if (validationErrors.length > 0) {
            throw new Error(`(UNEXPECTED) newly created secretIbGib has validationErrors? validationErrors: ${validationErrors} (E: 458708237973aea6c72121016d98af24)`);
        }
        // save first in the space...
        await metaspace.persistTransformResult({ resTransform: resFirstGen, space });
        // register the new secret with the ibgib space in general...
        await metaspace.registerNewIbGib({ ibGib: secretIbGib, space });
        // register the new secret with the secrets index
        await metaspace.rel8ToSpecialIbGib({
            type: "secrets",
            rel8nName: SECRET_REL8N_NAME,
            ibGibsToRel8: [secretIbGib],
            space,
        });
        // localIndex_secretIbGibs = await metaspace.getSpecialRel8dIbGibs({
        //     type: "secrets",
        //     rel8nName: SECRET_REL8N_NAME,
        //     space,
        // });
        return secretIbGib;
    }
    catch (error) {
        console.error(`${lc} ${extractErrorMsg(error)}`);
        throw error;
    }
    finally {
        if (logalot) {
            console.log(`${lc} complete.`);
        }
    }
}
/**
 * executes the hash16816 fn on the incoming {@link password} using parameters
 * {@link recursionCount}, {@link saltPrependedPerHash} and {@link algorithm}.
 * Then selects a random contiguous substring of {@link substringLength} of the
 * resultant hash.
 *
 * @returns {@link substringLength} of deterministic hash
 *
 * This is a novel idea only useful in a byzantine fault tolerant distributed
 * computation context, so to understand how this is used, PLEASE...
 * @see {@link CheckIfPasswordProbablyCorrectInfo}
 */
export async function getCheckIfPasswordProbablyCorrectInfo({ password, substringLength, recursionCount, saltPrependedPerHash, algorithm, }) {
    const lc = `[${getCheckIfPasswordProbablyCorrectInfo.name}]`;
    try {
        if (logalot) {
            console.log(`${lc} starting... (I: 9dc41fcf83a6d0e6054d3a9e79803224)`);
        }
        if (!substringLength) {
            throw new Error(`substringLength (${substringLength}) required (E: d1d4fbfaa1562abac7ec42cdd0264224)`);
        }
        recursionCount ??= 16816;
        algorithm ??= 'SHA-256';
        const fullHash = await hash16816({
            s: password,
            algorithm: 'SHA-256',
            recursionCount,
            saltPrependedPerHash,
        });
        // we want to pick a random starting point for the substring. on the
        // consuming end, we don't need to know this random index, we will just
        // confirm that the fullHash generated when the user enters their
        // password conatins this substring at all (not where it starts from).
        // 64 = length of sha256 hash
        // 64-1 = 0-indexed adjustment
        const r = Math.random();
        const substringStartIndex = Math.floor(r * (63 - substringLength));
        const resSubstring = fullHash.substring(substringStartIndex, substringStartIndex + substringLength);
        // defensive checks here (atow 02/2024), remove at some point once we
        // see that this isn't throwing and it's tested well enough
        if (resSubstring.length !== substringLength) {
            throw new Error(`(UNEXPECTED) resSubstring.length (${resSubstring.length}) !== substringLength (${substringLength})?\nfullHash: ${fullHash}\nr: ${r}\nsubstringStartIndex: ${substringStartIndex}\nresSubstring: ${resSubstring}(E: c45acd126b4c70041e92f6ad5329c424)`);
        }
        const confirmResult = await passwordProbablyCorrect({
            password, checkInfo: {
                substring: resSubstring,
                algorithm,
                recursionCount,
                saltPrependedPerHash,
            }
        });
        if (!confirmResult) {
            throw new Error(`(UNEXPECTED) !confirmResult? uhh... (E: cc757a8ef07b6468793b1bddbafca924)`);
        }
        return {
            substring: resSubstring,
            saltPrependedPerHash: saltPrependedPerHash ?? '',
            recursionCount,
            algorithm,
        };
    }
    catch (error) {
        console.error(`${lc} ${extractErrorMsg(error)}`);
        throw error;
    }
    finally {
        if (logalot) {
            console.log(`${lc} complete.`);
        }
    }
}
/**
 * confirmation side of verifying if a consumer's password is **probably**
 * correct. Basically computes the silly hash of the password and checks to see
 * if it contains the given substring.
 *
 * @see {@link CheckIfPasswordProbablyCorrectInfo}
 * @see {@link getCheckIfPasswordProbablyCorrectInfo}
 */
export async function passwordProbablyCorrect({ password, checkInfo, }) {
    const lc = `[${passwordProbablyCorrect.name}]`;
    try {
        if (logalot) {
            console.log(`${lc} starting... (I: ce745a0d8b5de7a24ddc83fe432e4224)`);
        }
        const { substring, recursionCount, saltPrependedPerHash, algorithm } = checkInfo;
        const fullHash = await hash16816({
            s: password,
            recursionCount,
            saltPrependedPerHash,
            algorithm,
        });
        const resProbablyCorrect = fullHash.includes(substring);
        return resProbablyCorrect;
    }
    catch (error) {
        console.error(`${lc} ${extractErrorMsg(error)}`);
        throw error;
    }
    finally {
        if (logalot) {
            console.log(`${lc} complete.`);
        }
    }
}
//# sourceMappingURL=secret-helper.mjs.map