import { resourceManager } from '../utilities/resource-manager.js';
export class ReactRootManager {
    constructor() {
        this.roots = new Map();
        this.renderingRoots = new Set();
        this.unmountQueue = new Map();
        this.hooks = [];
        this.firstRootCreated = false;
    }
    RegisterHook(hook) {
        this.hooks.push(hook);
    }
    RemoveHook(hookName) {
        const index = this.hooks.findIndex(h => h.name === hookName);
        if (index >= 0) {
            this.hooks.splice(index, 1);
            return true;
        }
        return false;
    }
    createRoot(container, createRootFn, componentId) {
        const rootId = `react-root-${Date.now()}-${Math.random()}`;
        const root = createRootFn(container);
        const managedRoot = {
            id: rootId,
            root,
            container,
            isRendering: false,
            componentId
        };
        this.roots.set(rootId, managedRoot);
        if (componentId) {
            resourceManager.registerReactRoot(componentId, root, () => this.unmountRoot(rootId));
        }
        const hookContext = { rootId, container, componentId };
        if (!this.firstRootCreated) {
            this.firstRootCreated = true;
            this.invokeHooks('OnFirstRootCreated', hookContext);
        }
        this.invokeHooks('OnRootCreated', hookContext);
        return rootId;
    }
    render(rootId, element, onComplete) {
        const managedRoot = this.roots.get(rootId);
        if (!managedRoot) {
            console.warn(`React root ${rootId} not found`);
            return;
        }
        if (this.unmountQueue.has(rootId)) {
            console.warn(`React root ${rootId} is being unmounted, skipping render`);
            return;
        }
        managedRoot.isRendering = true;
        this.renderingRoots.add(rootId);
        try {
            managedRoot.root.render(element);
            managedRoot.lastRenderTime = new Date();
            Promise.resolve().then(() => {
                managedRoot.isRendering = false;
                this.renderingRoots.delete(rootId);
                const pendingUnmount = this.unmountQueue.get(rootId);
                if (pendingUnmount) {
                    this.unmountQueue.delete(rootId);
                    pendingUnmount();
                }
                if (onComplete) {
                    onComplete();
                }
            });
        }
        catch (error) {
            managedRoot.isRendering = false;
            this.renderingRoots.delete(rootId);
            throw error;
        }
    }
    unmountRoot(rootId, force = false) {
        return new Promise((resolve) => {
            const managedRoot = this.roots.get(rootId);
            if (!managedRoot) {
                resolve();
                return;
            }
            const performUnmount = () => {
                try {
                    managedRoot.root.unmount();
                    this.roots.delete(rootId);
                    this.renderingRoots.delete(rootId);
                    if (managedRoot.container) {
                        delete managedRoot.container._reactRootContainer;
                        managedRoot.container.innerHTML = '';
                    }
                    this.invokeHooks('OnRootUnmounted', rootId);
                    resolve();
                }
                catch (error) {
                    console.error(`Error unmounting React root ${rootId}:`, error);
                    this.roots.delete(rootId);
                    this.renderingRoots.delete(rootId);
                    resolve();
                }
            };
            if (!managedRoot.isRendering || force) {
                performUnmount();
            }
            else {
                this.unmountQueue.set(rootId, () => {
                    performUnmount();
                });
            }
        });
    }
    async unmountComponentRoots(componentId) {
        const rootIds = [];
        for (const [rootId, managedRoot] of this.roots) {
            if (managedRoot.componentId === componentId) {
                rootIds.push(rootId);
            }
        }
        await Promise.all(rootIds.map(id => this.unmountRoot(id)));
    }
    isRendering(rootId) {
        return this.renderingRoots.has(rootId);
    }
    getStats() {
        return {
            totalRoots: this.roots.size,
            renderingRoots: this.renderingRoots.size,
            pendingUnmounts: this.unmountQueue.size
        };
    }
    async cleanup() {
        this.invokeHooks('OnCleanup');
        const allRootIds = Array.from(this.roots.keys());
        await Promise.all(allRootIds.map(id => this.unmountRoot(id, true)));
        this.firstRootCreated = false;
    }
    invokeHooks(method, arg) {
        for (const hook of this.hooks) {
            const fn = hook[method];
            if (typeof fn === 'function') {
                try {
                    fn.call(hook, arg);
                }
                catch (error) {
                    console.error(`Error in runtime hook "${hook.name}" during ${method}:`, error);
                }
            }
        }
    }
}
export const reactRootManager = new ReactRootManager();
//# sourceMappingURL=react-root-manager.js.map