import { StrictMode } from "react";
import { flushSync } from "react-dom";
import { createRoot } from "react-dom/client";

import "./main.scss";

import { defaultMountingTarget, defaultOptions } from "./constants";
import type { ChatOptions } from "./types";
import { createDefaultMountingTarget } from "./utils";

import { ChatProvider } from "./providers/ChatProvider";
import App from "./App";

export interface ChatInstance {
	unmount: () => void;
	element: Element | null;
}

export function createChat(options?: Partial<ChatOptions>): ChatInstance {
	const resolvedOptions: ChatOptions = {
		...defaultOptions,
		...options,
		webhookConfig: {
			...defaultOptions.webhookConfig,
			...options?.webhookConfig,
		},
		i18n: {
			...defaultOptions.i18n,
			...options?.i18n,
			en: {
				...defaultOptions.i18n?.en,
				...options?.i18n?.en,
			},
		},
		theme: {
			...defaultOptions.theme,
			...options?.theme,
		},
	};

	const mountingTarget = resolvedOptions.target ?? defaultMountingTarget;

	if (typeof mountingTarget === "string") {
		createDefaultMountingTarget(mountingTarget);
	}

	const element =
		typeof mountingTarget === "string"
			? (document.querySelector(mountingTarget) as Element | null)
			: (mountingTarget as Element | null);

	if (!element) {
		throw new Error(
			`Failed to mount chat widget. Target "${String(mountingTarget)}" was not found.`,
		);
	}

	const root = createRoot(element);

	const appTree = (
		<ChatProvider options={resolvedOptions}>
			<App />
		</ChatProvider>
	);

	const shouldUseStrictMode = process.env.NODE_ENV !== "test";
	const tree = shouldUseStrictMode ? (
		<StrictMode>{appTree}</StrictMode>
	) : (
		appTree
	);

	flushSync(() => {
		root.render(tree);
	});

	return {
		unmount: () => root.unmount(),
		element,
	};
}
