import { createRoot as createRootOriginal } from "react-dom/client";

import type { ReactNode } from "react";
import type { Container } from "react-dom/client";

declare global {
    let __webpack_get_script_filename__: (chunkName: string) => string;
    let __webpack_public_path__: string;
}

const untrailingslashit = (str: string): string =>
    str.endsWith("/") || str.endsWith("\\") ? untrailingslashit(str.slice(0, -1)) : str;
const trailingslashit = (str: string): string => `${untrailingslashit(str)}/`;

// Allows to make an interface extension and make some properties optional (https://git.io/JeK6J)
type AllKeyOf<T> = T extends never ? never : keyof T;
type Optional<T, K> = { [P in Extract<keyof T, K>]?: T[P] };
type WithOptional<T, K extends AllKeyOf<T>> = T extends never ? never : Omit<T, K> & Optional<T, K>;

// Allows to extract a Generic (https://stackoverflow.com/a/50924506/5506547)
type TypeWithGeneric<T> = T[];
type ExtractGeneric<Type> = Type extends TypeWithGeneric<infer X> ? X : never;

/**
 * Renders a React component using either createRoot from react-dom/client (React 18+) or render from ReactDOM (React 17 and below).
 *
 * This is currently only needed for Divi compatibility as Divi is still using React v16 and WordPress < 6.2 as it uses React v17.
 *
 * We are using a custom webpack configuration to replace the react-dom/client dependency with our own package.
 *
 * @see https://app.clickup.com/t/86959qqq1
 * @deprecated When we drop support for WordPress < 6.2 we can safely migrate to `createRoot()`
 */
function createRoot(container: Container) {
    try {
        return createRootOriginal(container);
    } catch (error) {
        return {
            render: (element: ReactNode) => (window as any).ReactDOM?.render?.(element, container),
            unmount: () => (window as any).ReactDOM?.unmountComponentAtNode?.(container),
        };
    }
}

export {
    untrailingslashit,
    trailingslashit,
    type AllKeyOf,
    type Optional,
    type WithOptional,
    type ExtractGeneric,
    createRoot,
};
