/**
 * 文件定义：日期处理
 */

import * as R from 'ramda'

/* -------------- 1、日期处理 -------------- */
/**
 * 格式化时间格式
 * @param {string | number | Date} date - 日期字符串、时间戳、Date 对象
 * @param {string} format - 格式化字符串
 * @returns {string} 格式化后的日期字符串
 */
export const formatDate = (date: string | number | Date, format: string = 'yyyy-MM-dd HH:mm:ss'): string => {
	// 处理秒级时间戳
	const timestamp = !!Number(date) && date.toString().length === 10 ? new Date(Number(date) * 1000) : new Date(date)

	// 使用Ramda创建日期映射
	const dateMap = R.zipObj(
		['yyyy', 'MM', 'dd', 'HH', 'mm', 'ss'],
		[
			timestamp.getFullYear(),
			timestamp.getMonth() + 1,
			timestamp.getDate(),
			timestamp.getHours(),
			timestamp.getMinutes(),
			timestamp.getSeconds(),
		],
	)

	// 使用Ramda的reduce函数替换格式字符串中的占位符
	return R.reduce(
		(result: string, key: string) => {
			const value = dateMap[key as keyof typeof dateMap]
			// 将单位数的月、日、时、分、秒前面补0
			const formattedValue = key !== 'yyyy' && value < 10 ? `0${value}` : `${value}`
			// 使用正则表达式全局替换所有匹配项
			return result.replace(new RegExp(key, 'g'), formattedValue)
		},
		format,
		R.keys(dateMap),
	)
}

/**
 * 获取两个日期之间的天数差
 * @param {string | number | Date} startDate - 开始日期
 * @param {string | number | Date} endDate - 结束日期
 * @returns {number} 天数差
 */
export const getDaysDiff = (startDate: string | number | Date, endDate: string | number | Date): number => {
	const start = new Date(startDate)
	const end = new Date(endDate)
	const startDay = new Date(start.getFullYear(), start.getMonth(), start.getDate())
	const endDay = new Date(end.getFullYear(), end.getMonth(), end.getDate())
	const diff = endDay.getTime() - startDay.getTime()
	return Math.floor(diff / (1000 * 60 * 60 * 24))
}

/**
 * 柯里化版本的getDaysDiff
 * @param {string | number | Date} startDate - 开始日期
 * @param {string | number | Date} endDate - 结束日期
 * @returns {number} 天数差
 */
export const getDaysDiffCurried: {
	(startDate: string | number | Date, endDate: string | number | Date): number
	(startDate: string | number | Date): (endDate: string | number | Date) => number
} = R.curry(getDaysDiff)

/**
 * 判断日期是否在指定范围内
 * @param {string | number | Date} date - 要判断的日期
 * @param {string | number | Date} startDate - 开始日期
 * @param {string | number | Date} endDate - 结束日期
 * @returns {boolean} 是否在范围内
 */
export const isDateInRange = (
	date: string | number | Date,
	startDate: string | number | Date,
	endDate: string | number | Date,
): boolean => {
	const targetTime = new Date(date).getTime()
	const startTime = new Date(startDate).getTime()
	const endTime = new Date(endDate).getTime()
	return targetTime >= startTime && targetTime <= endTime
}

/**
 * 柯里化版本的isDateInRange
 * @param {string | number | Date} date - 要判断的日期
 * @param {string | number | Date} startDate - 开始日期
 * @param {string | number | Date} endDate - 结束日期
 * @returns {boolean} 是否在范围内
 */
export const isDateInRangeCurried: {
	(date: string | number | Date, startDate: string | number | Date, endDate: string | number | Date): boolean
	(date: string | number | Date): {
		(startDate: string | number | Date, endDate: string | number | Date): boolean
		(startDate: string | number | Date): (endDate: string | number | Date) => boolean
	}
	(date: string | number | Date, startDate: string | number | Date): (endDate: string | number | Date) => boolean
} = R.curry(isDateInRange)

/**
 * 获取指定日期的开始时间（00:00:00）
 * @param {string | number | Date} date - 日期
 * @returns {Date} 日期的开始时间
 */
export const getStartOfDay = (date: string | number | Date): Date => {
	const d = new Date(date)
	return new Date(d.getFullYear(), d.getMonth(), d.getDate())
}

/**
 * 获取指定日期的结束时间（23:59:59）
 * @param {string | number | Date} date - 日期
 * @returns {Date} 日期的结束时间
 */
export const getEndOfDay = (date: string | number | Date): Date => {
	const d = new Date(date)
	return new Date(d.getFullYear(), d.getMonth(), d.getDate(), 23, 59, 59, 999)
}

/**
 * 添加天数到指定日期
 * @param {number} days - 要添加的天数
 * @param {string | number | Date} date - 日期
 * @returns {Date} 新日期
 */
export const addDays = (days: number, date: string | number | Date): Date => {
	const result = new Date(date)
	result.setDate(result.getDate() + days)
	return result
}

// 柯里化版本的addDays
export const addDaysCurried: {
	(days: number, date: string | number | Date): Date
	(days: number): (date: string | number | Date) => Date
} = R.curry(addDays)

/**
 * 格式化相对时间（如：刚刚、x分钟前、x小时前、x天前）
 * @param {string | number | Date} date - 日期
 * @returns {string} 格式化后的相对时间
 */
export const formatRelativeTime = (date: string | number | Date): string => {
	const now = new Date().getTime()
	const target = new Date(date).getTime()
	const diff = now - target

	if (diff < 1000 * 60) {
		return '刚刚'
	} else if (diff < 1000 * 60 * 60) {
		return `${Math.floor(diff / (1000 * 60))}分钟前`
	} else if (diff < 1000 * 60 * 60 * 24) {
		return `${Math.floor(diff / (1000 * 60 * 60))}小时前`
	} else if (diff < 1000 * 60 * 60 * 24 * 30) {
		return `${Math.floor(diff / (1000 * 60 * 60 * 24))}天前`
	} else {
		return formatDate(date, 'YYYY-MM-DD')
	}
}

/**
 * 获取指定日期是星期几
 * @param {string | number | Date} date - 日期
 * @returns {string} 星期几
 */
export const getDayOfWeek = (date: string | number | Date): string => {
	const days = ['日', '一', '二', '三', '四', '五', '六']
	return `星期${days[new Date(date).getDay()]}`
}

/**
 * 获取指定距离到期时间
 * @param {string | number | Date} date - 日期
 * @param {string | number | Date} expirationDate - 到期日期, 默认当前时间
 * @returns {string} 距离到期时间
 */
export const getDaysUntilExpiration = (
	date: string | number | Date,
	expirationDate: string | number | Date = new Date(),
): string => {
	const target = new Date(date)
	const expiration = new Date(expirationDate)
	const diff = expiration.getTime() - target.getTime()
	const days = Math.floor(diff / (1000 * 60 * 60 * 24))
	return days > 0 ? `${days}天` : '已过期'
}
