import { extractErrorMsg, getSaferSubstring } from "@ibgib/helper-gib/dist/helpers/utils-helper.mjs";
import { getIbAndGib, getIbGibAddr } from "@ibgib/ts-gib/dist/helper.mjs";
import { rel8 } from "@ibgib/ts-gib/dist/V1/transforms/rel8.mjs";
import { Factory_V1 } from "@ibgib/ts-gib/dist/V1/factory.mjs";
import { GLOBAL_LOG_A_LOT } from "../../core-constants.mjs";
import { ALIAS_ATOM, ALIAS_MAX_LENGTH, ALIAS_REL8N_NAME, ALIAS_TARGET_REL8N_NAME, DEFAULT_ALIAS_DESCRIPTION } from "./alias-constants.mjs";
import { SpecialIbGibType } from "../other/other-types.mjs";
const logalot = GLOBAL_LOG_A_LOT;
/**
 * relates an ibgib provided by {@link ibGib} or {@link addr} to the latest
 * version of the given {@link aliasIbGib}.
 *
 * If the alias already exists, this will replace the target ibgib with the ibgib passed in.
 * if the alias does not exist, this will create the new alias first.
 *
 * persists this result in the same {@link space} and registers the newly
 * created alias ibgib via the {@link metaspace}.
 *
 * @returns the new/latest alias ibgib
 *
 * @throws an error if the aliases special ibgib index does not exist in the
 * given {@link space}
 *
 * @see {@link ALIAS_TARGET_REL8N_NAME}
 */
export async function setAlias({ ibGib, addr, aliasIbGib, aliasName, metaspace, space, lock, }) {
    const lc = `[${setAlias.name}]`;
    try {
        if (logalot) {
            console.log(`${lc} starting... (I: f6a2969d2948482cac073467a010fe1b)`);
        }
        if (addr && ibGib && addr !== getIbGibAddr({ ibGib })) {
            throw new Error(`both addr (${addr}) and ibGib (${getIbGibAddr({ ibGib })}) are provided but addr does not match addr of ibGib. (E: a0bfe5acf9c643cbbd20cc3936580ce9)`);
        }
        if (!addr && !ibGib) {
            throw new Error(`either addr or ibGib required (E: 8f02309770504046960c64fae00c0fcc)`);
        }
        addr ??= getIbGibAddr({ ibGib });
        let aliasAddr = aliasIbGib ?
            getIbGibAddr({ ibGib: aliasIbGib }) :
            undefined;
        if (!aliasIbGib) {
            // get the alias ibgib if exists. if doesn't exist, will create
            // later in code
            if (!aliasName) {
                throw new Error(`(UNEXPECTED) !aliasIbGib && !aliasName? either aliasIbGib or aliasName required (E: 7dda32d1803ac02b4c80f415fd726f24)`);
            }
            let info = await getAliasInfo({ aliasName, metaspace, space, lock });
            if (info) {
                aliasIbGib = info.ibGib;
                aliasAddr = getIbGibAddr({ ibGib: aliasIbGib });
            }
        }
        let newAliasIbGib;
        let latestAliasAddr = aliasAddr ?
            await metaspace.getLatestAddr({ addr: aliasAddr, space }) :
            undefined;
        if (latestAliasAddr) {
            // alias exists, so update
            if (!aliasIbGib || latestAliasAddr !== getIbGibAddr({ ibGib: aliasIbGib })) {
                let resGetLatestAlias = await metaspace.get({ addr: latestAliasAddr, space });
                if (!resGetLatestAlias.success || resGetLatestAlias.ibGibs?.length !== 1) {
                    throw new Error(`could not get latest alias (${latestAliasAddr}) from space (${space.ib}). error: ${resGetLatestAlias.errorMsg ?? '[unknown error (E: faae3a4b5f6b4e28b99d089f1a8be13a)]'} (E: c5fc6dc7326242e48618b240266e63b7)`);
                }
                aliasIbGib = resGetLatestAlias.ibGibs.at(0);
                aliasAddr = getIbGibAddr({ ibGib: aliasIbGib });
            }
            // at this point, the aliasIbGib and its addr are guaranteed to be
            // truthy and latest
            const rel8nsToAddByAddr = { [ALIAS_TARGET_REL8N_NAME]: [addr] };
            const resRel8ToAlias = await rel8({
                src: aliasIbGib,
                rel8nsToAddByAddr,
                // linked because an alias only points to a single target
                linkedRel8ns: [ALIAS_TARGET_REL8N_NAME],
                dna: true, nCounter: true,
            });
            newAliasIbGib = resRel8ToAlias.newIbGib;
            await metaspace.persistTransformResult({ resTransform: resRel8ToAlias, space });
            // update the special ibgib index to point to the new alias
            const _newAliasesIndexIbGib = await metaspace.rel8ToSpecialIbGib({
                type: SpecialIbGibType.aliases,
                rel8nName: ALIAS_REL8N_NAME,
                space,
                ibGibsToRel8: [newAliasIbGib],
                ibGibsToUnRel8: [aliasIbGib],
            });
        }
        else {
            // alias does not yet exist, so create new
            if (!aliasName) {
                throw new Error(`(UNEXPECTED) !latestAliasAddr and !aliasName? alias should either exist in space (${space.ib}) and have a latest addr or aliasName should be provided. (E: ab1cc9d24f356b888f877131d5dff824)`);
            }
            const saferizedAliasName = getSaferSubstring({ text: aliasName });
            const resNewAlias = await Factory_V1.firstGen({
                parentIbGib: Factory_V1.primitive({ ib: ALIAS_ATOM }),
                ib: `${ALIAS_ATOM} ${saferizedAliasName}`,
                data: {
                    name: saferizedAliasName,
                    rawName: aliasName, // just in case probably yagni yada yada
                    description: DEFAULT_ALIAS_DESCRIPTION,
                },
                // linked because an alias only points to a single target
                linkedRel8ns: [ALIAS_TARGET_REL8N_NAME],
                tjp: { uuid: true, timestamp: true },
                dna: true,
                nCounter: true,
            });
            newAliasIbGib = resNewAlias.newIbGib;
            await metaspace.persistTransformResult({ resTransform: resNewAlias, space });
            const _newAliasesIndexIbGib = await metaspace.rel8ToSpecialIbGib({
                type: SpecialIbGibType.aliases,
                rel8nName: ALIAS_REL8N_NAME,
                space,
                ibGibsToRel8: [newAliasIbGib],
            });
        }
        await metaspace.registerNewIbGib({ ibGib: newAliasIbGib, space });
        return newAliasIbGib;
    }
    catch (error) {
        console.error(`${lc} ${extractErrorMsg(error)}`);
        throw error;
    }
    finally {
        if (logalot) {
            console.log(`${lc} complete.`);
        }
    }
}
/**
 * gets the alias ibgib and sundry based on given `aliasName`.
 *
 * @returns info about the alias registered or undefined if no matching alias
 * exists
 */
export async function getAliasInfo({ aliasName, metaspace, lock, space, }) {
    const lc = `[${getAliasInfo.name}]`;
    try {
        if (logalot) {
            console.log(`${lc} starting... (I: 40bc11ee4d0e182047ffa28d046a0324)`);
        }
        if (aliasName.length > ALIAS_MAX_LENGTH) {
            throw new Error(`invalid aliasName. cannot be greater than ALIAS_MAX_LENGTH (${ALIAS_MAX_LENGTH}). (E: b1a03c3893519b8bdbaef52ee1d4ab24)`);
        }
        // get the alias via aliasName from the special ibgib index
        let aliasesIbGib = await metaspace.getSpecialIbGib({
            type: SpecialIbGibType.aliases,
            initialize: false,
            lock,
            space,
        });
        if (!aliasesIbGib) {
            throw new Error(`no aliases special ibgib (index) exists in given space (${space.ib}). This index must be initialized first. (E: 7f4cb726cafb93534e2d893945867b24)`);
        }
        // find the alias
        const saferizedAliasName = getSaferSubstring({ text: aliasName });
        let rel8dTargets = (aliasesIbGib.rel8ns ?? {})[ALIAS_TARGET_REL8N_NAME] ?? [];
        // alias ibs atow (04/2024) are just `alias_atom saferizedAliasName`
        let aliasAddr = rel8dTargets.find(aliasAddr => {
            let { ib: targetAliasIb } = getIbAndGib({ ibGibAddr: aliasAddr });
            let saferizedAliasName_target = targetAliasIb.substring(`${ALIAS_ATOM} `.length);
            return saferizedAliasName_target === saferizedAliasName;
        });
        if (aliasAddr) {
            let latestAliasAddr = await metaspace.getLatestAddr({ addr: aliasAddr, space });
            if (!latestAliasAddr) {
                throw new Error(`(UNEXPECTED) alias addr exists on special ibgib in space but getLatestAddr returns falsy? (E: 854b7209fe851ee4ea4034d5db229924)`);
            }
            let resGetLatestAlias = await metaspace.get({ addr: latestAliasAddr, space });
            if (!resGetLatestAlias.success || resGetLatestAlias.ibGibs?.length !== 1) {
                throw new Error(`could not get latest alias (${latestAliasAddr}) from space (${space.ib}). error: ${resGetLatestAlias.errorMsg ?? '[unknown error (E: 3f4a79a1603c40e285816a81d693a488)]'} (E: b2e8fe50fbbc44a5ac973c23d3a40fef)`);
            }
            let aliasIbGib = resGetLatestAlias.ibGibs.at(0);
            if (!aliasIbGib.rel8ns) {
                throw new Error(`(UNEXPECTED) !aliasIbGib.rel8ns? (E: 1d78faaf1c73c27d5cee2edbd1a14a24)`);
            }
            if (!aliasIbGib.rel8ns[ALIAS_TARGET_REL8N_NAME]) {
                throw new Error(`(UNEXPECTED) !aliasIbGib.rel8ns[ALIAS_TARGET_REL8N_NAME]? (E: b7b2d8ac1c3d6e910b56891e56c9ab24)`);
            }
            if (aliasIbGib.rel8ns[ALIAS_TARGET_REL8N_NAME].length !== 1) {
                throw new Error(`(UNEXPECTED) aliasIbGib.rel8ns[ALIAS_TARGET_REL8N_NAME].length !== 1? (E: 8da0d9566ca9c6b8519f46157404eb24)`);
            }
            return {
                ibGib: aliasIbGib,
                targetAddr: aliasIbGib.rel8ns[ALIAS_TARGET_REL8N_NAME].at(0),
                rawName: aliasName,
                saferizedName: saferizedAliasName,
            };
        }
        else {
            return undefined;
        }
    }
    catch (error) {
        console.error(`${lc} ${extractErrorMsg(error)}`);
        throw error;
    }
    finally {
        if (logalot) {
            console.log(`${lc} complete.`);
        }
    }
}
// todo: removeAlias function
// todo: updateAlias function
//# sourceMappingURL=alias-helper.mjs.map