import React, { useEffect, useRef } from 'react';

import { createPortal } from 'react-dom';

// @ts-ignore
import config from '../../../../../nitrogen.config.js';

export default React.forwardRef(function IFrame(
	{ children, inspectorWidth, onClick, ...props }: any,
	ref: any
) {
	const addedStyles = useRef(false);
	const headElId = useRef(0);

	const mountNode = ref.current?.contentWindow?.document?.body;
	useEffect(() => {
		const targetNode = document.querySelector('head');
		if (targetNode) {
			const config = { childList: true, subtree: true };

			// Callback function to execute when mutations are observed
			const callback = (
				mutationList: MutationRecord[],
				observer: MutationObserver
			) => {
				for (const mutation of mutationList) {
					if (mutation.type === 'childList') {
						// console.log('A child node has been added or removed.');
						// console.log(mutation);
						// console.log(mutation.addedNodes.length && mutation.addedNodes[0]);
						// console.log(
						// 	mutation.removedNodes.length && mutation.removedNodes[0]
						// );

						mutation.addedNodes.forEach((node) => {
							if (!(node as HTMLElement).getAttribute('data-nitrogen-id')) {
								(node as HTMLElement).setAttribute(
									'data-nitrogen-id',
									`${headElId.current++}`
								);
							}
						});

						removeNodes(mutation.removedNodes);
						addNodes(mutation.addedNodes);
					}
				}
				// clearStyles();
				// addStyles();
			};

			// Create an observer instance linked to the callback function
			const observer = new MutationObserver(callback);

			// Start observing the target node for configured mutations
			observer.observe(targetNode, config);

			return () => {
				observer.disconnect();
			};
		}
	}, []);

	function removeNodes(nodes: NodeList) {
		// remove nodes from ref.current.contentWindow.document.head

		if (!ref.current || !ref.current.contentWindow) return;

		for (let i = 0; i < nodes.length; i++) {
			const node = nodes[i] as HTMLElement;

			// check if attributes match
			const attributes = node.attributes;
			const headNodes = ref.current.contentWindow.document.head.childNodes;

			const dataViteDevId = node.getAttribute('data-vite-dev-id') ?? '';

			for (let j = 0; j < headNodes.length; j++) {
				const headNode = headNodes[j] as HTMLElement;

				if (headNode.tagName !== node.tagName) continue;

				let match = true;
				for (let k = 0; k < attributes.length; k++) {
					const attribute = attributes[k];
					if (headNode.getAttribute(attribute.name) !== attribute.value) {
						match = false;
						break;
					}
				}

				if (
					match &&
					(!import.meta.env.DEV ||
						dataViteDevId.indexOf('/node_modules/simplebar-react') === -1)
				) {
					// console.log('headNode matches node, removing headNode', {
					//   headNode,
					//   node,
					// });
					headNode.remove();
					break;
				}
			}
		}
	}

	function addNodes(nodes: NodeList) {
		// add nodes to ref.current.contentWindow.document.head

		if (!ref.current || !ref.current.contentWindow) return;

		for (let i = 0; i < nodes.length; i++) {
			const node = nodes[i] as HTMLElement;

			// check if attributes match and if so, remove and add new node
			const attributes = node.attributes;
			const headNodes = ref.current.contentWindow.document.head.childNodes;

			const dataViteDevId = node.getAttribute('data-vite-dev-id') ?? '';

			for (let j = 0; j < headNodes.length; j++) {
				const headNode = headNodes[j] as HTMLElement;

				if (headNode.tagName !== node.tagName) continue;

				let match = true;
				for (let k = 0; k < attributes.length; k++) {
					const attribute = attributes[k];
					if (headNode.getAttribute(attribute.name) !== attribute.value) {
						match = false;
						break;
					}
				}

				if (
					match &&
					(!import.meta.env.DEV ||
						dataViteDevId.indexOf('/node_modules/simplebar-react') === -1)
				) {
					// console.log(
					//   'node matches headNode, removing headNode, going to add node',
					//   {
					//     headNode,
					//     node,
					//   }
					// );
					headNode.remove();
					break;
				}
			}

			// console.log('adding node', { node });
			ref.current.contentWindow.document.head.appendChild(node.cloneNode(true));
		}
	}

	function clearStyles() {
		if (!ref.current || !ref.current.contentWindow) return;

		ref.current.contentWindow.document.head.innerHTML = '';
	}

	function addStyles() {
		const els = document.head.querySelectorAll(
			import.meta.env.DEV ? 'style' : 'style, link:not([data-noiframe])'
		);

		if (!ref.current || !ref.current.contentWindow) return;

		for (let i = 0; i < els.length; i++) {
			// Skip Nitrogen styles
			const dataViteDevId = els[i].getAttribute('data-vite-dev-id') ?? '';
			const href = els[i].getAttribute('href') ?? '';

			if (
				import.meta.env.DEV &&
				dataViteDevId.indexOf('@nitrogenbuilder/core/src/tw.scss') === -1 &&
				dataViteDevId.indexOf('@nitrogenbuilder/core/src/Bob.scss') === -1 &&
				(dataViteDevId.indexOf('@nitrogenbuilder/core/src/') > -1 ||
					(dataViteDevId.indexOf(
						'@nitrogenbuilder/core/node_modules/simplebar-react'
					) === -1 &&
						dataViteDevId.indexOf('@nitrogenbuilder/core/node_modules/') > -1))
			)
				continue;

			if (!els[i].getAttribute('data-nitrogen-id')) {
				els[i].setAttribute('data-nitrogen-id', `${headElId.current++}`);
			}

			ref.current.contentWindow.document.head.appendChild(
				els[i].cloneNode(true)
			);
		}

		const style = document.createElement('style');
		style.innerHTML = config.cssInjection;
		ref.current.contentWindow.document.head.appendChild(style);

		addedStyles.current = true;
	}

	useEffect(() => {
		if (ref.current && ref.current.contentWindow) {
			if (!addedStyles.current && mountNode) {
				addStyles();

				// add event listener to show context menu on right click in iframe
				ref.current.contentDocument.addEventListener(
					'contextmenu',
					(e: MouseEvent) => {
						e.preventDefault();
					}
				);
				if (onClick) {
					ref.current.contentDocument.addEventListener('click', onClick);
				}
			}
		}
	}, [ref.current]);

	return (
		<iframe
			id='editor-iframe'
			{...props}
			width='100%'
			height='100%'
			resize='0'
			scrolling='0'
			ref={ref}
		>
			{mountNode && createPortal(children, mountNode)}
		</iframe>
	);
});
