import { usePluginReady } from '@greenpay/hooks'
import { settingsDispatch } from '@greenpay/redux'
import { Root } from 'react-dom/client'
import { createRoot, useEffect, useRef } from '@wordpress/element'
import GreenPayClassic from './app/GreenPayClassic'
import { MOUNT, ROOT } from './data/constants'

import './installHydrationGuard'
import '@greenpay/store'
import './utils/eventEmitter'

if (document.getElementById(MOUNT) && window.greenmoney_wpApiSettings) {
	settingsDispatch().setSettings(window.greenmoney_wpApiSettings)
}

const Bootstrap: React.FC = () => {
	const settings = usePluginReady()
	const classicRootRef = useRef<Root>()

	useEffect(() => {
		if (!settings) return

		const rafId = requestAnimationFrame(async () => {
			try {
				const container = document.getElementById(MOUNT)
				if (!container) {
					return
				}

				if (classicRootRef.current) {
					classicRootRef.current.unmount()
				}

				classicRootRef.current = createRoot(container)
				classicRootRef.current.render(
					<GreenPayClassic
						title={settings.title}
						description={settings.description}
						extraMessage={settings.extraMessage}
					/>,
				)
				container.dataset.reactRendered = 'true'
			} catch (error) {
				console.error('[GreenPay] Classic checkout bootstrap failed', error)
			}
		})

		return () => {
			cancelAnimationFrame(rafId)
		}
	}, [settings])

	return null
}

let root: Root
let bootstrapRenderCount = 0
let mountTimeout: ReturnType<typeof setTimeout> | null = null
let observerInitialized = false

function mount() {
	let rootWrapper = document.getElementById(ROOT)
	if (!rootWrapper) {
		rootWrapper = document.createElement('div')
		rootWrapper.id = ROOT
		document.body.appendChild(rootWrapper)
	}

	if (!root) {
		root = createRoot(rootWrapper)
	}

	bootstrapRenderCount++
	root.render(<Bootstrap key={bootstrapRenderCount} />)
}

function observeAndMount() {
	const container = document.getElementById(MOUNT)
	if (container) {
		container.dataset.reactRendered = 'false'
	}

	if (mountTimeout) clearTimeout(mountTimeout)
	mountTimeout = setTimeout(() => {
		mount()
	}, 50)

	if (!observerInitialized) {
		const observer = new MutationObserver((mutations) => {
			const hasMountElementChange = mutations.some((mutation) => {
				return Array.from(mutation.addedNodes).some((node) => {
					if (node.nodeType === Node.ELEMENT_NODE) {
						const element = node as Element
						return element.id === MOUNT || element.querySelector(`#${MOUNT}`)
					}
					return false
				})
			})

			if (hasMountElementChange) {
				const mountContainer = document.getElementById(MOUNT)

				if (mountContainer) {
					if (mountTimeout) clearTimeout(mountTimeout)
					mountTimeout = setTimeout(() => {
						mount()
						mountContainer.dataset.reactRendered = 'true'
					}, 50)
				}
			}
		})

		observer.observe(document.body, {
			childList: true,
			subtree: true,
		})
		observerInitialized = true
	}
}

function startClassicCheckout() {
	if (document.readyState === 'loading') {
		document.addEventListener('DOMContentLoaded', () => {
			setTimeout(() => {
				observeAndMount()
			}, 10)
		})
	} else {
		observeAndMount()
	}
}

startClassicCheckout()

if (window.jQuery) {
	window.jQuery(document.body).on('updated_checkout', () => {
		if (mountTimeout) clearTimeout(mountTimeout)
		mountTimeout = setTimeout(() => {
			mount()
		}, 50)
	})
}

window.greenpayRepaint = observeAndMount
window.greenpayBoot = mount
