<script setup lang="ts">
import type { ToolbarConfig } from './richTextTypes'
import { CodeEditor, copyText, Btn } from '@bagelink/vue'
import { watch, onUnmounted, ref } from 'vue'
import EditorToolbar from './components/EditorToolbar.vue'
import { useCommands } from './composables/useCommands'
import { useEditor } from './composables/useEditor'
import { useEditorKeyboard } from './composables/useEditorKeyboard'

const props = defineProps<{ modelValue: string, toolbarConfig?: ToolbarConfig, debug?: boolean, label?: string }>()
const emit = defineEmits(['update:modelValue'])

const iframe = ref<HTMLIFrameElement>()
const editor = useEditor()
const isInitializing = ref(false)
const hasInitialized = ref(false)

// Initialize content from modelValue
editor.state.content = props.modelValue

// Initialize debugger if debug mode is enabled
if (props.debug) {
	editor.initDebugger()
}

const commands = useCommands(editor.state, editor.state.debug)

// Expose debug methods if debug mode is enabled
const debugMethods = $computed(() => editor.state.debug)
const hasRTL = $computed(() => /[\u0591-\u07FF\uFB1D-\uFDFD\uFE70-\uFEFC]/.test(props.modelValue))

// Cleanup on component unmount
onUnmounted(() => {
	editor.cleanup()
})

async function initEditor() {
	if (isInitializing.value || !iframe.value || hasInitialized.value) {
		return
	}

	isInitializing.value = true

	try {
		// Load styles first
		const editorStyles = await import('./editor.css?inline')

		// Create a complete HTML document with proper doctype and meta tags
		const htmlContent = `
			<!DOCTYPE html>
			<html>
			<head>
				<meta charset="UTF-8">
				<meta name="viewport" content="width=device-width, initial-scale=1.0">
				<meta http-equiv="Content-Security-Policy" content="
					default-src * data: blob: 'unsafe-inline' 'unsafe-eval';
					img-src * data: blob:;
					style-src * 'unsafe-inline';
					script-src * 'unsafe-inline' 'unsafe-eval';
					frame-src * data: blob:;
					connect-src *;
					media-src *;
				">
				<base target="_blank">
				<style id="editor-styles">${editorStyles.default}</style>
			</head>
			<body>${props.modelValue || ''}</body>
			</html>
		`

		// Write the complete HTML document to the iframe
		const doc = iframe.value.contentDocument || iframe.value.contentWindow?.document
		if (!doc) return

		// First write the content
		doc.open()
		// ! @deprecated — MDN Reference[https://developer.mozilla.org/en-US/docs/Web/API/Document/write]
		doc.write(htmlContent)
		doc.close()

		// Then make it editable after a short delay
		await new Promise(resolve => setTimeout(resolve, 0))

		doc.designMode = 'on'
		doc.body.contentEditable = 'true'

		// Set default direction based on content
		doc.body.dir = hasRTL ? 'rtl' : 'ltr'

		// Ensure editor.state.content is set to the current HTML content
		editor.state.content = doc.body.innerHTML

		editor.init(doc)
		useEditorKeyboard(doc, commands)

		// Initial cleanup and ensure there's at least one paragraph
		if (!doc.body.firstElementChild) {
			const p = doc.createElement('p')
			p.dir = doc.body.dir
			p.innerHTML = '<br>'
			doc.body.appendChild(p)
			// Update state.content after changes
			editor.state.content = doc.body.innerHTML
		} else {
			// Convert any direct text nodes to paragraphs
			const walker = doc.createTreeWalker(doc.body, NodeFilter.SHOW_TEXT)
			const textNodes: Text[] = []
			let node: Node | null
			while ((node = walker.nextNode())) {
				if (node.parentElement === doc.body) {
					textNodes.push(node as Text)
				}
			}
			textNodes.forEach((textNode) => {
				if (textNode.textContent?.trim()) {
					const p = doc.createElement('p')
					p.dir = doc.body.dir
					p.appendChild(textNode.cloneNode())
					doc.body.replaceChild(p, textNode)
				} else {
					doc.body.removeChild(textNode)
				}
			})
			// Update state.content after cleanup
			editor.state.content = doc.body.innerHTML
		}

		doc.body.focus()
		hasInitialized.value = true
	} catch (error) {
		// Keep only this error log for debugging critical issues
		console.error('Error during editor initialization:', error)
	} finally {
		isInitializing.value = false
	}
}

// Reset initialization state when content changes significantly
watch(() => props.modelValue, (newValue, oldValue) => {
	if (newValue !== editor.state.content) {
		// Only reset if content change is significant (not just minor edits)
		if (!oldValue || Math.abs(newValue.length - oldValue.length) > 50) {
			hasInitialized.value = false
			editor.state.content = newValue
			editor.updateState.content('html')
		}
	}
})

watch(() => editor.state.content, (newValue) => {
	if (editor.state.doc?.body) {
		editor.state.doc.body.dir = hasRTL ? 'rtl' : 'ltr'
	}
	emit('update:modelValue', newValue)
})
</script>

<template>
	<div class="bagel-input">
		<label>{{ label }}</label>
		<div class="rich-text-editor rounded pt-05 px-05 pb-075" :class="{ 'fullscreen-mode': editor.state.isFullscreen }">
			<EditorToolbar
				v-if="editor.state.hasInit" :config="toolbarConfig" :selectedStyles="editor.state.selectedStyles"
				@action="commands.execute"
			/>
			<div class="editor-container" :class="{ 'split-view': editor.state.isSplitView }">
				<div class="content-area radius-05">
					<iframe
						id="rich-text-iframe"
						ref="iframe"
						class="editableContent"
						title="Editor"
						srcdoc=""
						sandbox="allow-same-origin allow-forms allow-modals allow-orientation-lock allow-pointer-lock allow-popups allow-popups-to-escape-sandbox allow-presentation allow-scripts allow-top-navigation allow-top-navigation-by-user-activation"
						@load="initEditor"
					/>
				</div>
				<CodeEditor
					v-if="editor.state.isSplitView"
					v-model="editor.state.content"
					language="html"
					:height="editor.state.isFullscreen ? 'calc(100vh - 4rem)' : '250px'"
					@update:modelValue="editor.updateState.content('html')"
				/>
			</div>
			<div v-if="debug" class="flex">
				<p class="text12 txt-gray mb-0 p-0">
					Debug
				</p>
				<Btn thin color="gray" icon="delete" @click="debugMethods?.clearSession">
					Clear Session
				</Btn>
				<Btn thin color="gray" icon="download" @click="debugMethods?.downloadSession">
					Download Log
				</Btn>
				<Btn thin color="gray" icon="content_copy" @click="copyText(debugMethods?.exportDebugWithPrompt() || '')">
					Copy Log
				</Btn>
			</div>
		</div>
	</div>
</template>

<style>
.content-area p,
.content-area span,
.content-area li{
	line-height: 1.65;
}
</style>

<style scoped>
.rich-text-editor {
	background: var(--input-bg);
	border: 1px solid var(--border-color);
	transition: all 0.3s ease;
}

.editor-container {
	display: flex;
	gap: 0.5rem;
}

.content-area,
.preview-area {
	flex: 1;
	min-height: 200px;
	background: var(--bgl-richtext-color);
}

.split-view {
	display: grid;
	grid-template-columns: 1fr 1fr;
}

.editableContent {
	width: 100%;
	min-height: 240px;
	height: 100%;
	border: none;
	outline: none;
	background: transparent;
}

.html-editor {
	width: 100%;
	height: 100%;
	min-height: 200px;
	font-family: monospace;
	border: none;
	outline: none;
	resize: none;
	color: white;
	background-color: var(--bgl-black);
}

.preview-area {
	font-family: monospace;
	white-space: pre-wrap;
	overflow-x: auto;
}

.fullscreen-mode {
	position: fixed;
	top: 0;
	left: 0;
	width: 100vw;
	height: 100vh;
	z-index: 9999;
	padding: 2rem;
}

.fullscreen-mode .editor-container {
	height: calc(100vh - 4rem);
}

.fullscreen-mode .content-area,
.fullscreen-mode .preview-area {
	height: 100%;
	overflow-y: auto;
}

.debug-controls {
	display: flex;
	gap: 0.5rem;
	justify-content: flex-end;
}
</style>
