const pool: Record<string, string> = {};
const recreateFetchPool: Record<string, Promise<string>> = {};

/**
 * A REST nonce in WordPress is only valid for 12 hours (can be configured). However, if it gets
 * invalid, the REST endpoints return a `403` error which signals us, we should recreate the nonce.
 * To avoid multiple recreations, we memorize the newly created nonce in a pool.
 */
function nonceDeprecationPool(nonce: string): Promise<string>;
function nonceDeprecationPool(nonce: string, restRecreateNonceEndpoint: string): Promise<string>;
async function nonceDeprecationPool(nonce: string, restRecreateNonceEndpoint?: string): Promise<string> {
    if (typeof restRecreateNonceEndpoint !== "undefined") {
        const resultPromise =
            // Reuse already sent request
            recreateFetchPool[nonce] ||
            new Promise<string>(
                // eslint-disable-next-line no-async-promise-executor
                async (resolve, reject) => {
                    try {
                        const recreateFetch = await window.fetch(restRecreateNonceEndpoint, {
                            method: "POST",
                        });

                        if (recreateFetch.ok) {
                            const newNonce = await recreateFetch.text();
                            if (nonce === newNonce) {
                                reject();
                            } else {
                                pool[nonce] = newNonce;
                                resolve(newNonce);
                            }
                        } else {
                            reject();
                        }
                    } catch (e) {
                        reject();
                    }
                },
            );

        recreateFetchPool[nonce] = resultPromise;

        // Remove from pool when request is done
        resultPromise.finally(() => {
            delete recreateFetchPool[nonce];
        });

        return resultPromise;
    } else {
        if (typeof nonce === "undefined") {
            return undefined;
        }

        // Wait until all nonces are refreshed
        await Promise.all(Object.values(recreateFetchPool));

        let returnNonce = nonce;

        while (pool[returnNonce]) {
            returnNonce = pool[returnNonce];

            if (pool[returnNonce] === nonce) {
                break;
            }
        }

        return Promise.resolve(returnNonce);
    }
}

export { nonceDeprecationPool };
