package timeutil

import "time"

type IndexedYear struct {
	Year   int            `json:"year"`
	Months []IndexedMonth `json:"months"`
}

type IndexedMonth struct {
	Number time.Month `json:"number"`
	Name   string     `json:"name"`
	Days   []int      `json:"days"`
}

type DayIndexer struct {
	monthNames     []string
	lastDayOfMonth int
	hourCorrection time.Duration
	index          []IndexedYear
	year           *IndexedYear
	month          *IndexedMonth
	day            int
}

type DayIndexerOptions struct {
	Lang           string
	LastDayOfMonth int
	FirstHourOfDay int
}

func NewDayIndexer(opt DayIndexerOptions) *DayIndexer {
	s := new(DayIndexer)
	if opt.FirstHourOfDay > 0 {
		s.hourCorrection = -time.Duration(opt.FirstHourOfDay) * time.Hour
	}
	s.lastDayOfMonth = opt.LastDayOfMonth

	var ok bool
	s.monthNames, ok = monthNames[opt.Lang]
	if !ok {
		s.monthNames = monthNames[defaultLang]
	}
	return s
}

func (s *DayIndexer) Add(timestamp int64) {
	tm := time.Unix(timestamp, 0)

	if s.hourCorrection > 0 {
		tm.Add(s.hourCorrection)
	}

	monthNumber := tm.Month()
	if s.lastDayOfMonth > 0 {
		if tm.Day() > s.lastDayOfMonth {
			monthNumber++
		}
	}

	if s.year == nil {
		s.year = &IndexedYear{
			Year: tm.Year(),
		}
		s.month = &IndexedMonth{
			Number: monthNumber,
			Name:   s.monthNames[monthNumber-1],
		}
		s.day = tm.Day()
	} else {
		if s.year.Year != tm.Year() {
			s.month.Days = append(s.month.Days, s.day)
			s.year.Months = append(s.year.Months, *s.month)
			s.index = append(s.index, *s.year)

			s.year = &IndexedYear{
				Year: tm.Year(),
			}
			s.month = &IndexedMonth{
				Number: monthNumber,
				Name:   s.monthNames[monthNumber-1],
			}
			s.day = tm.Day()
		} else if s.month.Number != monthNumber {
			s.month.Days = append(s.month.Days, s.day)
			s.year.Months = append(s.year.Months, *s.month)

			s.month = &IndexedMonth{
				Number: monthNumber,
				Name:   s.monthNames[monthNumber-1],
			}
			s.day = tm.Day()
		} else if s.day != tm.Day() {
			s.month.Days = append(s.month.Days, s.day)
			s.day = tm.Day()
		}
	}
}

func (s *DayIndexer) GetIndex() []IndexedYear {
	index := s.index
	if s.year != nil {
		// Хитрая конструкция нужна для двух случаев:
		// - повторный вызов GetIndex вернет такой же результат;
		// - вызовы Add после GetIndex продолжат корректно заполнять индекс, а
		// последующие вызовы GetIndex вернут корректные индексы.
		month := *s.month
		month.Days = append(month.Days, s.day)
		year := *s.year
		year.Months = append(year.Months, month)
		index = append(index, year)
	}
	return index
}
