package utils

import (
	"agent/commons/utime"
	"agent/internal/include"
	"fmt"
)

// NextWorkTime возвращает время в наносекундах, когда приложение сможет начать работу.
// Возвращает 0, если текущее время уже рабочее, иначе ближайшее время начала работы.
func NextWorkTime(schedule *include.ScheduleCfg, currentTime utime.Time, maxDaysAhead ...int) int64 {
	if IsWorkTime(schedule, currentTime) {
		// Уже рабочее время, нечего ждать
		return 0
	}

	// Значение по умолчанию — 365 дней вперёд
	maxDays := 7
	if len(maxDaysAhead) > 0 {
		maxDays = maxDaysAhead[0]
	}

	for i := 0; i <= maxDays; i++ {
		checkDay := currentTime.AddDate(0, 0, i)

		startTime := utime.Date(
			checkDay.Year(), checkDay.Month(), checkDay.Day(),
			schedule.Work.Time.Start.Hour,
			schedule.Work.Time.Start.Minute,
			0,
		)

		// Проверяем: если начало этого дня — уже рабочее время
		if IsWorkTime(schedule, startTime) {
			// Если день тот же — но уже позже стартового времени, пропускаем
			if i == 0 && !startTime.After(currentTime) {
				continue
			}
			return int64(startTime.Sub(currentTime).Seconds())
		}
	}

	// Если в пределах maxDayAhead не найдено рабочего времени
	return -1
}

func IsWorkTime(schedule *include.ScheduleCfg, currentTime utime.Time) bool {
	hour := currentTime.Hour()
	minute := currentTime.Minute()

	currentMinutes := hour*60 + minute
	startMinutes := schedule.Work.Time.Start.Hour*60 + schedule.Work.Time.Start.Minute
	endMinutes := schedule.Work.Time.End.Hour*60 + schedule.Work.Time.End.Minute

	isWorkTime := false
	if startMinutes == 0 && endMinutes == 0 {
		// Если часы работы не заданы, то считаем, что агент может работать круглосуточно
		isWorkTime = true
	} else {
		// Поддержка интервала с переходом через полночь
		if startMinutes <= endMinutes {
			// Проверка интервал в пределах одних суток
			isWorkTime = currentMinutes >= startMinutes && currentMinutes < endMinutes
		} else {
			// Проверка интервала с переходом через полночь (например, 09:00 - 04:00)
			isWorkTime = currentMinutes >= startMinutes || currentMinutes < endMinutes
		}
	}
	if !isWorkTime {
		return false
	}

	year := fmt.Sprintf("%d", currentTime.Year())
	dayOfYear := currentTime.YearDay()
	if makeyupDays, ok := schedule.MakeupDays[year]; ok {
		for _, day := range makeyupDays {
			if dayOfYear == day {
				return true
			}
		}
	}
	if holidays, ok := schedule.Hollidays[year]; ok {
		for _, holiday := range holidays {
			if dayOfYear == holiday {
				return false
			}
		}
	}

	currentDay := currentTime.Weekday()
	return isWorkDay(schedule, currentDay)
}

func isWorkDay(schedule *include.ScheduleCfg, day utime.Weekday) bool {
	switch day {
	case utime.Monday:
		return schedule.Work.Days.Monday
	case utime.Tuesday:
		return schedule.Work.Days.Tuesday
	case utime.Wednesday:
		return schedule.Work.Days.Wednesday
	case utime.Thursday:
		return schedule.Work.Days.Thursday
	case utime.Friday:
		return schedule.Work.Days.Friday
	case utime.Saturday:
		return schedule.Work.Days.Saturday
	case utime.Sunday:
		return schedule.Work.Days.Sunday
	default:
		return false
	}
}
