import { readonly, ref } from 'vue'

import enUs from './locales/en-us'
import zhCn from './locales/zh-cn'

export type LocaleType = 'zh-cn' | 'en-us'
type TranslateParams = Record<string, string | number>

type MessageSchema = typeof zhCn

const STORAGE_KEY = 'locale'

const messages: Record<LocaleType, MessageSchema> = {
	'zh-cn': zhCn,
	'en-us': enUs
}

const getInitialLocale = (): LocaleType => {
	if (typeof window === 'undefined') {
		return 'zh-cn'
	}

	const savedLocale = localStorage.getItem(STORAGE_KEY) as LocaleType | null

	if (savedLocale && savedLocale in messages) {
		return savedLocale
	}

	return 'zh-cn'
}

const locale = ref<LocaleType>(getInitialLocale())

const resolveMessage = (targetLocale: LocaleType, key: string) => {
	return key.split('.').reduce<unknown>((value, currentKey) => {
		if (value && typeof value === 'object') {
			return (value as Record<string, unknown>)[currentKey]
		}

		return undefined
	}, messages[targetLocale])
}

const formatMessage = (message: string, params?: TranslateParams) => {
	if (!params) {
		return message
	}

	return message.replace(/\{(\w+)\}/g, (matched, token) => {
		const value = params[token]
		return value === undefined ? matched : String(value)
	})
}

const tm = (key: string): unknown => {
	const currentMessage = resolveMessage(locale.value, key)

	if (currentMessage !== undefined) {
		return currentMessage
	}

	return resolveMessage('zh-cn', key)
}

const setLocale = (nextLocale: LocaleType) => {
	if (!(nextLocale in messages)) {
		return
	}

	locale.value = nextLocale

	if (typeof window !== 'undefined') {
		localStorage.setItem(STORAGE_KEY, nextLocale)
	}
}

const t = (key: string, params?: TranslateParams): string => {
	const currentMessage = tm(key)

	if (typeof currentMessage === 'string') {
		return formatMessage(currentMessage, params)
	}
	return key
}

const i18n = {
	locale: readonly(locale),
	setLocale,
	getLocale: () => locale.value,
	tm,
	t
}

export default i18n
