// composables/useTheme.ts
import { ref, computed, onMounted, watch } from 'vue'

export interface ThemeOption {
	value: string
	class: string
	icon: string
	label: string
	isDark?: boolean
}

const themeOptions = ref<ThemeOption[]>([
	{
		value: 'dark',
		class: 'bgl-dark-mode',
		icon: 'cloudy_night',
		label: 'Dark Mode',
		isDark: true,
	},
	{
		value: 'light',
		class: 'bgl-light-mode',
		icon: 'brightness_7',
		label: 'Light Mode',
		isDark: false,
	},
	{
		value: 'system',
		class: 'system',
		icon: 'settings_input_component',
		label: 'System Default',
	},
])

const STORAGE_KEY = 'color-mode'

const colorMode = ref<string>('system')
const isDark = ref(false)

const isBrowser = typeof window !== 'undefined'

function getSystemPrefersDark() {
	return isBrowser && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches
}

function findTheme(value: string) {
	return themeOptions.value.find(t => t.value === value)
}

function applyTheme(themeValue: string) {
	if (!isBrowser) return
	const root = document.documentElement

	// Remove all theme classes
	themeOptions.value.forEach((t) => {
		if (t.class !== 'system') {
			root.classList.remove(t.class)
		}
	})

	// Handle system theme
	if (themeValue === 'system') {
		const systemIsDark = getSystemPrefersDark()
		isDark.value = systemIsDark
		const darkTheme = themeOptions.value.find(t => t.value === 'dark')
		const lightTheme = themeOptions.value.find(t => t.value === 'light')
		const themeToApply = systemIsDark ? darkTheme : lightTheme
		if (themeToApply) {
			root.classList.add(themeToApply.class)
		}
	} else {
		// Apply the selected theme
		const theme = findTheme(themeValue)
		if (theme) {
			root.classList.add(theme.class)
			isDark.value = theme.isDark ?? false
		}
	}
}

function toggleTheme() {
	// Get all non-system themes
	const cyclableThemes = themeOptions.value.filter(t => t.value !== 'system')

	if (cyclableThemes.length === 0) { return }

	const currentIndex = cyclableThemes.findIndex(t => t.value === colorMode.value)
	const nextIndex = (currentIndex + 1) % cyclableThemes.length
	colorMode.value = cyclableThemes[nextIndex].value
}

function addTheme(theme: ThemeOption) {
	// Check if theme with this value already exists
	const exists = themeOptions.value.some(t => t.value === theme.value)
	if (!exists) {
		// Add before 'system' option
		const systemIndex = themeOptions.value.findIndex(t => t.value === 'system')
		if (systemIndex > -1) {
			themeOptions.value.splice(systemIndex, 0, theme)
		} else {
			themeOptions.value.push(theme)
		}
	}
}
/**
 * Provides a way to manage the theme of the application.
 *
 * The theme is stored in localStorage and can be toggled between 'dark', 'light', and 'system'.
 * The theme is applied to the document root's classList when the theme is active.
 * the classes are 'bgl-dark-mode', 'bgl-light-mode', and 'system'.
 *
 * Example usage:
 * const { theme, isDark, toggleTheme, addTheme, setTheme } = useTheme()
 * theme.value = 'dark'
 * isDark.value = true
 * toggleTheme()
 * addTheme({ value: 'ocean', label: 'Ocean Blue', class: 'ocean-blue', isDark: false })
 * setTheme('ocean')
 */

export function useTheme() {
	onMounted(() => {
		const saved = window.localStorage.getItem(STORAGE_KEY)
		const validTheme = themeOptions.value.find(t => t.value === saved)

		if (validTheme) {
			colorMode.value = saved!
		}

		// Apply initial theme
		applyTheme(colorMode.value)

		// React to system changes when in "system" mode
		const mq = window.matchMedia('(prefers-color-scheme: dark)')
		const handler = (e: MediaQueryListEvent) => {
			if (colorMode.value === 'system') {
				applyTheme('system')
			}
		}
		mq.addEventListener('change', handler)
	})

	// Watch for mode changes
	watch(colorMode, (newMode) => {
		if (isBrowser) localStorage.setItem(STORAGE_KEY, newMode)
		applyTheme(newMode)
	})

	const theme = computed(() => colorMode.value)

	return {
		isDark,
		theme,
		themeOptions,
		toggleTheme,
		addTheme,
		setTheme: (value: string) => {
			colorMode.value = value
		},
	}
}
