import type { HighlightJS, HighlightTheme } from './CodeTypes'
import { appendStyle, appendScript } from '@bagelink/vue'
import { ref } from 'vue'

// Extend the Window interface
interface CustomWindow extends Window {
	hljs: HighlightJS
}
declare const window: CustomWindow

export function useHighlight(theme: HighlightTheme = 'dark') {
	const hljs = ref<HighlightJS | null>(null)
	const loaded = ref(false)
	const currentTheme = ref<HighlightTheme>(theme)

	const normalizeTheme = (t: HighlightTheme): HighlightTheme => {
		if (t === 'dark') { return 'atom-one-dark' }
		if (t === 'light') { return 'atom-one-light' }
		return t
	}

	const getThemeCssUrl = (t: HighlightTheme) => `https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.0/styles/${t}.min.css`

	const removeExistingThemeLinks = () => {
		document.querySelectorAll('link[rel="stylesheet"]').forEach((link) => {
			if (link instanceof HTMLLinkElement && link.href.includes('/styles/')) {
				if (link.href.includes('highlight.js')) { link.parentElement?.removeChild(link) }
			}
		})
	}

	const setTheme = async (theme: HighlightTheme) => {
		const next = normalizeTheme(theme)
		if (next === currentTheme.value) { return }
		try {
			removeExistingThemeLinks()
			const url = getThemeCssUrl(next)
			console.log('setTheme', url)
			await appendStyle(url)
			currentTheme.value = next
		} catch (error) {
			console.error('Failed to apply theme. Falling back to atom-one-dark:', error)
			removeExistingThemeLinks()
			currentTheme.value = 'atom-one-dark'
			const url = getThemeCssUrl(currentTheme.value)
			await appendStyle(url)
		}
	}

	const loadHighlight = async () => {
		if (loaded.value) { return }

		try {
			// Load highlight.js
			await appendScript('https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.0/highlight.min.js', { id: 'hljs-cdn' })
			await setTheme(currentTheme.value)

			if (window.hljs) {
				hljs.value = window.hljs
				loaded.value = true
			} else {
				console.error('Failed to load highlight.js')
			}
		} catch (error) {
			console.error('Error loading highlight.js:', error)
		}
	}

	const escapeHtml = (unsafe: string) => {
		return unsafe.replace(/[&<>"']/g, (m) => {
			const replacements: { [key: string]: string } = {
				'&': '&amp;',
				'<': '&lt;',
				'>': '&gt;',
				'"': '&quot;',
				'\'': '&#039;'
			}
			return replacements[m] || ''
		})
	}

	const highlightCode = (code: string, language?: string, autodetect = true, ignoreIllegals = true) => {
		if (!hljs.value) { return escapeHtml(code) }

		try {
			const lang = language || ''

			if (lang && !autodetect && !hljs.value.getLanguage(lang)) {
				console.warn(`The language "${lang}" is not available.`)
				return escapeHtml(code)
			}

			const result = autodetect
				? hljs.value.highlightAuto(code)
				: hljs.value.highlight(code, { language: lang, ignoreIllegals })

			return result.value || escapeHtml(code)
		} catch (error) {
			console.error('Highlighting error:', error)
			return escapeHtml(code)
		}
	}

	return {
		hljs,
		loaded,
		loadHighlight,
		setTheme,
		currentTheme,
		escapeHtml,
		highlightCode
	}
}
