import { GENESIS_SLOT } from "@lodestar/params";
import { getValidatorStatus, mapToGeneralStatus, } from "@lodestar/types";
import { fromHex } from "@lodestar/utils";
import { ApiError, ValidationError } from "../../errors.js";
export function resolveStateId(forkChoice, stateId) {
    if (stateId === "head") {
        return forkChoice.getHead().stateRoot;
    }
    if (stateId === "genesis") {
        return GENESIS_SLOT;
    }
    if (stateId === "finalized") {
        return forkChoice.getFinalizedCheckpoint();
    }
    if (stateId === "justified") {
        return forkChoice.getJustifiedCheckpoint();
    }
    if (typeof stateId === "string" && stateId.startsWith("0x")) {
        return stateId;
    }
    // id must be slot
    const blockSlot = parseInt(String(stateId), 10);
    if (Number.isNaN(blockSlot) && Number.isNaN(blockSlot - 0)) {
        throw new ValidationError(`Invalid block id '${stateId}'`, "blockId");
    }
    return blockSlot;
}
export async function getStateResponseWithRegen(chain, inStateId) {
    const stateId = resolveStateId(chain.forkChoice, inStateId);
    const res = typeof stateId === "string"
        ? await chain.getStateByStateRoot(stateId, { allowRegen: true })
        : typeof stateId === "number"
            ? stateId > chain.clock.currentSlot
                ? null // Don't try to serve future slots
                : stateId >= chain.forkChoice.getFinalizedBlock().slot
                    ? await chain.getStateBySlot(stateId, { allowRegen: true })
                    : await chain.getHistoricalStateBySlot(stateId)
            : await chain.getStateOrBytesByCheckpoint(stateId);
    if (!res) {
        throw new ApiError(404, `State not found for id '${inStateId}'`);
    }
    return res;
}
export function toValidatorResponse(index, validator, balance, currentEpoch) {
    return {
        index,
        status: getValidatorStatus(validator, currentEpoch),
        balance,
        validator,
    };
}
export function filterStateValidatorsByStatus(statuses, state, pubkeyCache, currentEpoch) {
    const responses = [];
    const validatorsArr = state.validators.getAllReadonlyValues();
    const statusSet = new Set(statuses);
    for (const validator of validatorsArr) {
        const validatorStatus = getValidatorStatus(validator, currentEpoch);
        const generalStatus = mapToGeneralStatus(validatorStatus);
        const resp = getStateValidatorIndex(validator.pubkey, state, pubkeyCache);
        if (resp.valid && (statusSet.has(validatorStatus) || statusSet.has(generalStatus))) {
            responses.push(toValidatorResponse(resp.validatorIndex, validator, state.balances.get(resp.validatorIndex), currentEpoch));
        }
    }
    return responses;
}
export function getStateValidatorIndex(id, state, pubkeyCache) {
    if (typeof id === "string") {
        // mutate `id` and fallthrough to below
        if (id.startsWith("0x")) {
            try {
                id = fromHex(id);
            }
            catch (_e) {
                return { valid: false, code: 400, reason: "Invalid pubkey hex encoding" };
            }
        }
        else {
            id = Number(id);
        }
    }
    if (typeof id === "number") {
        const validatorIndex = id;
        // validator is invalid or added later than given stateId
        if (!Number.isSafeInteger(validatorIndex)) {
            return { valid: false, code: 400, reason: "Invalid validator index" };
        }
        if (validatorIndex >= state.validators.length) {
            return { valid: false, code: 404, reason: "Validator index from future state" };
        }
        return { valid: true, validatorIndex };
    }
    // typeof id === Uint8Array
    const validatorIndex = pubkeyCache.getIndex(id);
    if (validatorIndex === null) {
        return { valid: false, code: 404, reason: "Validator pubkey not found in state" };
    }
    if (validatorIndex >= state.validators.length) {
        return { valid: false, code: 404, reason: "Validator pubkey from future state" };
    }
    return { valid: true, validatorIndex };
}
//# sourceMappingURL=utils.js.map