package timeutils

import (
	"strconv"
	"time"

	"github.com/timandy/routine"
)

const (
	HOUR  = "hour"
	DAY   = "day"
	MONTH = "month"
)

func GetTimeAddr(date time.Time) *time.Time {
	return &date
}

func GetMonthDate(date time.Time) time.Time {
	date = date.UTC()
	return time.Date(date.Year(), date.Month(), 1, 0, 0, 0, 0, date.Location())
}

func GetMonthDateByYearMonth(year, month int) time.Time {
	return time.Date(year, time.Month(month), 1, 0, 0, 0, 0, time.UTC)
}

func GetMonthPeriodByYearMonth(year, month int) string {
	return time.Date(year, time.Month(month), 1, 0, 0, 0, 0, time.UTC).Format("01/02/06") + "-" +
		time.Date(year, time.Month(month+1), 1, 0, 0, 0, -1, time.UTC).Format("01/02/06")
}
func GetHourDate(date time.Time) time.Time {
	date = date.UTC()
	return time.Date(date.Year(), date.Month(), date.Day(), date.Hour(), 0, 0, 0, date.Location())
}

func GetDayDate(date time.Time) time.Time {
	date = date.UTC()
	return time.Date(date.Year(), date.Month(), date.Day(), 0, 0, 0, 0, date.Location())
}

func GetLastMonth(date time.Time) time.Time {
	return GetMonthDate(date).AddDate(0, -1, 0)
}
func GetLast2Month(date time.Time) time.Time {
	return GetMonthDate(date).AddDate(0, -2, 0)
}

func GetMonthDateForMonthlyWorkerByHours(date time.Time, hours int) time.Time {
	monthStartTime := GetMonthDate(date)
	if int(date.Sub(monthStartTime).Hours()) >= hours {
		return monthStartTime.AddDate(0, -1, 0)
	}
	return monthStartTime.AddDate(0, -2, 0)
}

func FromUnixTimeString(s string) (time.Time, error) {
	t, err := strconv.ParseInt(s, 10, 64)
	if err != nil {
		return time.Time{}, err
	}
	return time.Unix(t, 0), nil

}

var BaseNowFunc = func() time.Time {
	return time.Now().UTC()
}

var GetNowFunc = BaseNowFunc

var nowFuncLocalStorage = routine.NewThreadLocal[NowFunc]()

func GetNow() time.Time {
	nowFunc := nowFuncLocalStorage.Get()
	if nowFunc == nil {
		nowFunc = GetNowFunc
	}
	return nowFunc()
}

func GetNowAddr() *time.Time {
	now := GetNow()
	return &now
}

type NowFunc func() time.Time

func SetNowFunc(nowFunc NowFunc) {
	nowFuncLocalStorage.Set(nowFunc)
}

func SetMockNow(now time.Time) {
	SetNowFunc(func() time.Time {
		return now
	})
}

func GetMinTime(t1, t2 *time.Time) *time.Time {
	if t1 == nil {
		return t2
	}
	if t2 == nil {
		return t1
	}
	if t1.Before(*t2) {
		return t1
	}
	return t2
}

func GetNextMidnight(t time.Time) time.Time {
	nextMidnight := t
	formatTime := GetDayDate(nextMidnight)
	if nextMidnight.After(formatTime) {
		nextMidnight = formatTime.AddDate(0, 0, 1)
	}
	return nextMidnight
}
