package utils

import (
	"time"
)

// 定义时间格式常量
const (
	YearMonthDay     = "2006-01-02"                     // yyyy-MM-dd
	YearMonthDayTime = "2006-01-02 15:04:05"            // yyyy-MM-dd HH:mm:ss
	MonthDay         = "01-02"                          // MM-dd
	DayMonthYear     = "02-01-2006"                     // dd-MM-yyyy
	YearMonth        = "2006-01"                        // yyyy-MM
	FullDate         = "Monday, 02-Jan-06 15:04:05 PST" // 完整日期：例如：Monday, 02-Jan-06 15:04:05 PST
)

// GetPreYearTime 获取当前时间 前n年的时间 返回yyyy-MM-dd 格式的时间
func GetPreYearTime(n int) string {
	// 获取当前时间
	now := time.Now()
	// 计算前n年的时间
	preYearTime := now.AddDate(-n, 0, 0)
	// 格式化时间
	return preYearTime.Format("2006-01-02")
}

// IsMoreThanOneDay 判断两个yyyy-MM-dd类型的时间，相差是否大于1天
func IsMoreThanOneDay(startDate, endDate string) bool {
	startTime, _ := time.Parse("2006-01-02", startDate)
	endTime, _ := time.Parse("2006-01-02", endDate)
	diff := endTime.Sub(startTime)
	days := diff.Hours() / 24
	return days > 1
}

// GetNextDay 获取 yyyy-MM-dd类型的时间的下一天
func GetNextDay(date string) string {
	t, _ := time.Parse("2006-01-02", date)
	nextDay := t.AddDate(0, 0, 1)
	return nextDay.Format("2006-01-02")
}

// GetNextDayN 获取 yyyy-MM-dd 类型的时间的下n天
func GetNextDayN(date string, n int) string {
	t, _ := time.Parse("2006-01-02", date)
	nextDay := t.AddDate(0, 0, n)
	return nextDay.Format("2006-01-02")
}

var daysOfMonth = [...]int{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}

// AddDate 解决 Go time 包 AddDate() 添加年份/月份溢出到下一个月的问题。
// 例如:
//
//	2024-02-29 AddDate(1, 0, 0) 期望结果: 2025-02-28
//	2024-08-31 AddDate(0, 1, 1) 期望结果: 2024-09-30
func AddDate(t time.Time, years, months int) time.Time {
	month := t.Month()

	// 规范年份和月份
	years, months = norm(years, months, 12)

	// 计算目标月份
	targetMonth := int(month) + months
	if targetMonth <= 0 {
		// 处理负值月份
		targetMonth += 12 * ((-targetMonth)/12 + 1)
	}
	// 取余计算目标月份
	targetMonth = (targetMonth-1)%12 + 1

	// 计算目标年份
	targetYear := t.Year() + years + (int(month)+months-1)/12

	// 计算目标月份最大天数
	maxDayOfTargetMonth := daysOfMonth[targetMonth-1]
	if isLeap(targetYear) && targetMonth == 2 {
		maxDayOfTargetMonth++ // 闰年2月多一天
	}

	// 计算目标日期
	targetDay := t.Day()
	if targetDay > maxDayOfTargetMonth {
		// 如果目标日期超出该月的天数，设置为该月的最后一天
		targetDay = maxDayOfTargetMonth
	}

	// 返回新的日期
	return time.Date(targetYear, time.Month(targetMonth), targetDay, t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), t.Location())
}

// norm 规范化年份和月份
func norm(hi, lo, base int) (nhi, nlo int) {
	if lo < 0 {
		n := (-lo-1)/base + 1
		hi -= n
		lo += n * base
	}
	if lo >= base {
		n := lo / base
		hi += n
		lo -= n * base
	}
	return hi, lo
}

// isLeap 判断是否为闰年
func isLeap(year int) bool {
	return year%4 == 0 && (year%100 != 0 || year%400 == 0)
}

// StringToTime string 类型时间 转换为 time.Time 类型
func StringToTime(date string) time.Time {
	t, _ := time.ParseInLocation("2006-01-02", date, time.Local)
	return t
}

// StringToFormatTime string 类型时间 转换为指定格式的 time.Time类型
func StringToFormatTime(data string, format string) time.Time {
	t, _ := time.ParseInLocation(format, data, time.Local)
	return t
}

// TimeToString time.Time 类型时间 转换为 string 类型
func TimeToString(t time.Time, format string) string {
	formattedTime := t.Format(format)
	return formattedTime
}

// CompareDate 判断传入的两个字符串时间的前后顺序
func CompareDate(data1, data2 string) bool {
	t1, _ := time.Parse("2006-01-02", data1)
	t2, _ := time.Parse("2006-01-02", data2)
	return !t1.After(t2)
}
