import { setAuthenticationState } from "./set-authentication-state.js";
import { compare, hash } from "bcrypt";
import { isLike, isNumberString } from "../../is.js";
import { getOrigin } from "../../listen/index.js";
import { getAuthenticationState } from "./get-authentication-state.js";
import { getExpiresAt } from "../expiring-kv.js";
import { DEFAULT_INVITEE_STATE_EXPIRES_MS } from "./store.js";
import { nanoid } from "nanoid";
const { INVITEE_BCRYPT_SALT, INVITEE_BCRYPT_ROUNDS, INVITEE_URL, INVITEE_ORIGIN } = process.env;
const DEFAULT_INVITEE_URL = "/invite/accept";
const DEFAULT_ROUNDS = 13;
function getSaltOrRounds() {
    if (isNumberString(INVITEE_BCRYPT_ROUNDS)) {
        return +INVITEE_BCRYPT_ROUNDS;
    }
    else if (INVITEE_BCRYPT_SALT) {
        return INVITEE_BCRYPT_SALT;
    }
    return DEFAULT_ROUNDS;
}
export function getInviteURL(url) {
    return new URL(url || INVITEE_URL || DEFAULT_INVITEE_URL, INVITEE_ORIGIN || getOrigin());
}
export async function addInviteeState(data) {
    // Use a custom state id for human viewing
    const stateId = nanoid();
    const inviteSecret = nanoid(8);
    const inviteSecretHashed = await hash(inviteSecret, getSaltOrRounds());
    const intendedUrl = getInviteURL(data.inviteUrl);
    const inviteeState = {
        inviteSecretHashed,
        inviteUrl: intendedUrl.toString(),
        inviteAnonymous: !!data.inviteAnonymous,
        inviteAutoAccept: !!data.inviteAutoAccept,
        inviteRepeating: !!data.inviteRepeating,
        inviteRedirectUrl: data.inviteRedirectUrl,
        inviteChange: data.inviteChange
    };
    const state = await setAuthenticationState({
        ...data,
        stateId,
        type: "invitee",
        ...inviteeState,
        expiresAt: getExpiresAt(DEFAULT_INVITEE_STATE_EXPIRES_MS, data.expiresAt)
    });
    const inviteUrl = new URL(intendedUrl);
    // Set the token AFTER storing the target url in the database
    inviteUrl.searchParams.set("token", inviteSecret);
    inviteUrl.searchParams.set("state", stateId);
    return {
        ...state,
        ...inviteeState,
        inviteUrl: inviteUrl.toString()
    };
}
export async function getInviteeState({ stateId, token }) {
    const state = await getAuthenticationState(stateId);
    if (!state)
        return undefined;
    if (!isInviteeState(state))
        return undefined;
    const matched = await compare(token, state.inviteSecretHashed);
    if (!matched)
        return undefined;
    return state;
}
export function isInviteeState(state) {
    if (!state.type)
        return false;
    return !!(isLike(state) &&
        state.inviteUrl &&
        state.inviteSecretHashed);
}
export async function getExchangeStateURL(stateId) {
    if (!stateId)
        return undefined;
    const authState = await getAuthenticationState(stateId);
    if (authState?.type !== "exchange")
        return undefined;
    const exchangeState = await getAuthenticationState(authState.userState);
    if (exchangeState?.type !== "invitee")
        return undefined;
    const url = getInviteURL();
    url.searchParams.set("state", stateId);
    return url.toString();
}
//# sourceMappingURL=invite.js.map