import type { TimeUnit } from '../../types/timeAgoT'
import { timeDelta, formatDate, fmtDate, handleTimezone, getDatePartsMap } from '@bagelink/utils'
import { getI18n } from '../../i18n'

export { fmtDate, formatDate, getDatePartsMap, handleTimezone, timeDelta }
export type { DateTimeAcceptedFormats, FormatDateOptions } from '@bagelink/utils'

type TimeAgoLang = 'en' | 'es' | 'fr' | 'he' | 'it' | 'ru'

interface TimeAgoTranslations {
	year: string | TimeUnit
	month: string | TimeUnit
	week: string | TimeUnit
	day: string | TimeUnit
	hour: string | TimeUnit
	minute: string | TimeUnit
	second: string | TimeUnit
	ago: string
	in: string
	justNow: string
}

function getTimeAgoTranslations(lang: TimeAgoLang): TimeAgoTranslations {
	const fallback: TimeAgoTranslations = {
		year: 'year',
		month: 'month',
		week: 'week',
		day: 'day',
		hour: 'hour',
		minute: 'minute',
		second: 'second',
		ago: 'ago',
		in: 'in',
		justNow: 'Just now',
	}
	try {
		const i18n = getI18n()
		const messages = i18n.global.messages as Record<string, { timeAgo?: TimeAgoTranslations }>
		const localeMessages = messages[lang] || messages.en
		return localeMessages?.timeAgo ?? fallback
	} catch {
		return fallback
	}
}

function getCurrentLocale(): TimeAgoLang {
	try {
		const i18n = getI18n()
		const { locale } = i18n.global
		const lang = typeof locale === 'string' ? locale : locale.value
		const supported: TimeAgoLang[] = ['en', 'es', 'fr', 'he', 'it', 'ru']
		return supported.includes(lang as TimeAgoLang) ? lang as TimeAgoLang : 'en'
	} catch {
		return 'en'
	}
}

export function timeAgo(
	date: string | Date,
	langOrConfig?: TimeAgoLang | { lang?: TimeAgoLang, mode?: 'relative' | 'absolute' }
) {
	if (!date) return ''
	if (typeof date === 'string') date = new Date(date)

	const lang = typeof langOrConfig === 'string'
		? langOrConfig
		: (langOrConfig?.lang || getCurrentLocale())
	const mode = typeof langOrConfig === 'object' ? (langOrConfig.mode || 'relative') : 'relative'
	const isRelative = mode === 'relative'

	const seconds = Math.floor((date.getTime() - Date.now()) / 1000)
	const intervals = [
		{ label: 'year', seconds: 31536000 },
		{ label: 'month', seconds: 2592000 },
		{ label: 'week', seconds: 604800 },
		{ label: 'day', seconds: 86400 },
		{ label: 'hour', seconds: 3600 },
		{ label: 'minute', seconds: 60 },
		{ label: 'second', seconds: 1 },
	]

	const t = getTimeAgoTranslations(lang)
	const getUnit = (label: string): string | TimeUnit => t[label as keyof TimeAgoTranslations] as string | TimeUnit

	for (const interval of intervals) {
		const count = Math.floor(Math.abs(seconds) / interval.seconds)
		if (count >= 1) {
			const suffix = isRelative && seconds < 0 ? ` ${t.ago}` : ''
			const prefix = isRelative && seconds > 0 && t.in !== 'in' ? `${t.in} ` : ''

			if (lang === 'he') {
				const unit = getUnit(interval.label) as TimeUnit
				const form = count === 1 ? unit.singular : unit.plural
				const hePrefix = isRelative
					? (seconds < 0 ? `${t.ago} ` : (seconds > 0 ? `${t.in} ` : ''))
					: ''

				if (interval.label === 'day' && seconds > 0) {
					const hours = Math.floor((Math.abs(seconds) % 86400) / 3600)
					const hourUnit = t.hour as TimeUnit
					const hourForm = hours === 1 ? hourUnit.singular : hourUnit.plural
					const main = count === 1 ? form : `${count} ${form}`
					const hourPart = hours > 0 ? (hours === 1 ? ` ${hourForm}` : ` ${hours} ${hourForm}`) : ''
					return `${hePrefix}${main}${hourPart}`
				}
				return `${hePrefix}${count === 1 ? form : `${count} ${form}`}`
			}

			const label = getUnit(interval.label) as string
			if (interval.label === 'day' && seconds > 0) {
				const hours = Math.floor((Math.abs(seconds) % 86400) / 3600)
				const hourLabel = hours > 1 ? `${t.hour}s` : t.hour as string
				return `${prefix}${count} ${label}${hours > 0 ? ` ${hours} ${hourLabel}` : ''}${suffix}`
			}
			return `${prefix}${count} ${label}${suffix}`
		}
	}

	return t.justNow as string
}
