package helper

import (
	"fmt"
	"time"

	"github.com/pkg/errors"

	"google.golang.org/protobuf/types/known/timestamppb"
)

const (
	DefaultParseFormatLayout = "2006-1-02 15:04:05"         // 默认解析时间格式
	DefaultFormatLayout      = "2006-01-02 15:04:05"        // 默认时间格式
	MicroFormatLayout        = "2006-01-02 15:04:05.000000" // 微秒时间格式
	FormatLayout             = "20060102150405"             // 导出时间格式
)

func AfterMinutesUnix(minutes int64) int64 {
	// 获取当前时间
	currentTime := time.Now()
	// 将当前时间增加5分钟
	currentTime = currentTime.Add(time.Duration(minutes) * time.Minute)
	// 转换为Unix时间戳（秒）
	return currentTime.Unix()
}

func Parse(inputTime string) (time.Time, error) {
	// 设置时区为中国上海
	loc, err := time.LoadLocation("Asia/Shanghai")
	if err != nil {
		return time.Time{}, err
	}
	// 解析时间字符串并指定时区
	parsedTime, err := time.ParseInLocation(DefaultFormatLayout, inputTime, loc)
	if err != nil {
		return time.Time{}, err
	}
	return parsedTime, nil
}

func Parse2(timeStr string) (time.Time, error) {
	//if timeStr == "" {
	//	return time.Time{}, fmt.Errorf("时间参数未传递")
	//}
	//timeStr = strings.Replace(timeStr, "+", " ", -1)
	// 解析日期时间字符串
	t, err := time.Parse(DefaultFormatLayout, timeStr)
	if err != nil {
		return time.Time{}, err
	}
	// 获取本地时区的 *time.Location 对象
	local := time.Now().Location()
	// 将时间转换为本地时区的时间
	localTime := t.In(local)
	return localTime, nil
}

func DateStringToTime(localTimeStr string) (time.Time, error) {
	if localTimeStr == "" {
		return time.Time{}, fmt.Errorf("时间参数未传递")
	}
	layouts := []string{
		DefaultParseFormatLayout,
		DefaultFormatLayout,
		"2006-01-02 15:04",
		"2006-1-02 15:04",
		"2006-01-02",
		"2006-1-02",
		time.RFC3339Nano,
	}
	var (
		localTime time.Time
		err       error
	)
	loc, _ := time.LoadLocation(GetTimeZone())
	for _, layout := range layouts {
		localTime, err = time.ParseInLocation(layout, localTimeStr, loc)
		if err == nil {
			break
		}
	}
	if err != nil {
		return time.Time{}, fmt.Errorf("时间转换错误:%v", err)
	}

	return localTime, nil
}

// TimeFormat 时间戳转时间格式
func TimeFormat(inTime *time.Time, layout ...string) string {
	if inTime == nil {
		return ""
	}
	if len(layout) == 0 {
		layout = []string{DefaultFormatLayout}
	}
	return inTime.Format(layout[0])
}

// TimeStampFormat 时间戳转时间格式
func TimeStampFormat(timestamp int64, layout ...string) string {
	if timestamp == 0 {
		return ""
	}
	if len(layout) == 0 {
		layout = []string{DefaultFormatLayout}
	}
	return time.Unix(timestamp, 0).Format(layout[0])
}

// Int32TimeStampFormat int32类型时间戳转时间格式
func Int32TimeStampFormat(timestamp int32, layout ...string) string {
	return TimeStampFormat(int64(timestamp), layout...)
}

// IsoDateStringToTimeStamp iso格式字符串转时间戳
func IsoDateStringToTimeStamp(isoTimeStr string) (int64, error) {
	isoTime, err := time.ParseInLocation(time.RFC3339Nano, isoTimeStr, time.Local)
	if err != nil {
		return 0, err
	}
	return isoTime.Unix(), nil
}

// LayOutDateStringToTimeStamp layout格式字符串转时间戳
func LayOutDateStringToTimeStamp(localTimeStr string) (int64, error) {
	localTime, err := time.ParseInLocation(DefaultFormatLayout, localTimeStr, time.Local)
	if err != nil {
		return 0, err
	}
	return localTime.Unix(), nil
}

// DateStringToTimeStamp 字符串转时间戳(兼容格式)
func DateStringToTimeStamp(date string) (int64, error) {
	u, err := IsoDateStringToTimeStamp(date)
	if err != nil {
		u, err = LayOutDateStringToTimeStamp(date)
	}
	return u, err
}

// DateStringToTimeStampInt32 字符串转时间戳(兼容格式)
func DateStringToTimeStampInt32(date string) (int32, error) {
	u, err := DateStringToTimeStamp(date)
	return int32(u), err
}

// BatchDateStringToTimeStampInt32 批量字符串转时间戳
func BatchDateStringToTimeStampInt32(dates []string) ([]int32, error) {
	res := make([]int32, 0, len(dates))
	for _, date := range dates {
		u, err := DateStringToTimeStampInt32(date)
		if err != nil {
			return nil, err
		}
		res = append(res, u)
	}
	return res, nil
}

// GoogleTimeToString google proto时间转字符串
func GoogleTimeToString(date *timestamppb.Timestamp) string {
	loc, _ := time.LoadLocation(GetTimeZone())
	return date.AsTime().In(loc).Format(DefaultFormatLayout)
}

// GoogleTimeToMicroString google proto时间转字符串
func GoogleTimeToMicroString(date *timestamppb.Timestamp) string {
	loc, _ := time.LoadLocation(GetTimeZone())
	return date.AsTime().In(loc).Format(MicroFormatLayout)
}

func DateStringToTimeStampV2(localTimeStr string) (int64, error) {
	if localTimeStr == "" {
		return 0, nil
	}

	layouts := []string{
		DefaultParseFormatLayout,
		DefaultFormatLayout,
		"2006-01-02 15:04",
		"2006-1-02 15:04",
		"2006-01-02",
		"2006-1-02",
		time.RFC3339Nano,
	}

	var (
		localTime time.Time
		err       error
	)

	loc, _ := time.LoadLocation(GetTimeZone())
	for _, layout := range layouts {
		localTime, err = time.ParseInLocation(layout, localTimeStr, loc)
		if err == nil {
			break
		}
	}

	if err != nil {
		return 0, errors.Errorf("解析时间错误: %s", err.Error())
	}

	return localTime.Unix(), nil
}

// IsTimeStrBefore 时间比较 格式：2006-01-02 15:04:05
func IsTimeStrBefore(beforeTime, afterTime string) bool {
	time1, _ := time.Parse(DefaultFormatLayout, beforeTime)
	time2, _ := time.Parse(DefaultFormatLayout, afterTime)
	if time1.Before(time2) {
		return true
	}
	return false
}

// IsTimeBefore 时间比较 格式：2006-01-02 15:04:05,beforeTime[2024-01-10 00:00:00]小于afterTime[2024-01-02 00:00:00]返回true
func IsTimeBefore(beforeTime, afterTime time.Time) bool {
	if beforeTime.Before(afterTime) {
		return true
	}
	return false
}

// IsTimeBeforeOrEqual 时间比较 格式：2006-01-02 15:04:05,beforeTime[2024-01-10 00:00:00]小于等于afterTime[2024-01-02 00:00:00]返回true
func IsTimeBeforeOrEqual(beforeTime, afterTime time.Time) bool {
	b := beforeTime.Before(afterTime) || beforeTime.Equal(afterTime)
	if b {
		return true
	}
	return false
}

// IsInSameNaturalMonth 判断两个时间是否在同一个自然月
func IsInSameNaturalMonth(startTime, endTime time.Time) bool {
	// 将 startTime 和 endTime 的日期统一到该月的12号
	startYear, startMonth, _ := startTime.Date()
	endYear, endMonth, _ := endTime.Date()

	// 如果月份不同，调整 endTime 到 startTime 的同一天（同月）
	if startYear == endYear && startMonth == endMonth {
		return true
	}

	// 处理跨月情况, 检查如果 startTime 和 endTime 跨越到下一个月的同一天
	// 比如：如果 startTime 是 12 号，则 endTime 应该是下个月的12号
	expectedEndTime := time.Date(endYear, endMonth, startTime.Day(), startTime.Hour(), startTime.Minute(), startTime.Second(), 0, time.Local)

	// 如果 endTime 的日期和调整后的 expectedEndTime 相同，则认为它们属于同一个自然月
	return expectedEndTime.Year() == endTime.Year() &&
		expectedEndTime.Month() == endTime.Month() &&
		expectedEndTime.Day() == endTime.Day() &&
		expectedEndTime.Hour() == endTime.Hour() &&
		expectedEndTime.Minute() == endTime.Minute() &&
		expectedEndTime.Second() == endTime.Second()
}

func DaysBetween(start, end time.Time) (int, error) {
	// 2. 统一到同一天的 0 点（避免时分秒干扰）
	startDay := start.Truncate(24 * time.Hour)
	endDay := end.Truncate(24 * time.Hour)

	// 3. 计算天数（含结束日）
	days := int(endDay.Sub(startDay).Hours() / 24)
	if end.After(endDay) { // 结束时间非 0 点，加 1 天
		days++
	}

	return days, nil
}
