package notify

import (
	"fmt"
	"log"
	"time"

	tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
	"golang.org/x/exp/slices"
	"stud.l9labs.ru/bot/modules/api"
	"stud.l9labs.ru/bot/modules/database"
	"stud.l9labs.ru/bot/modules/ssauparser"
	"stud.l9labs.ru/bot/modules/tg"
	"xorm.io/xorm"
)

type Next struct {
	Lesson []database.Lesson
	Day    []database.Lesson
	Week   []database.Lesson
}

// –ü–æ–∏—Å–∫ —Å–ª–µ–¥—É—é—â–µ–π –ø–∞—Ä—ã, –¥–Ω—è, –Ω–µ–¥–µ–ª–∏
func CheckNext(db *xorm.Engine, now time.Time) ([]api.Notify, error) {
	now = now.Truncate(time.Minute)
	var completed []database.Lesson
	if err := db.
		Desc("Begin").
		Find(&completed, &database.Lesson{End: now}); err != nil {
		return nil, err
	}
	if len(completed) == 0 {
		return nil, nil
	}
	num := completed[0].NumInShedule + 1

	var next []database.Lesson
	if err := db.
		Where("date(`Begin`) = ? and NumInShedule = ?", now.Format("2006-01-02"), num).
		Find(&next); err != nil {
		return nil, err
	}
	var notify []api.Notify
	for _, n := range next {
		notify = append(notify, api.Notify{
			NoteType:  api.NextLesson,
			IsGroup:   true,
			SheduleID: n.GroupId,
			Lesson:    n,
		})
		if n.TeacherId != 0 {
			notify = append(notify, api.Notify{
				NoteType:  api.NextLesson,
				IsGroup:   false,
				SheduleID: n.TeacherId,
				Lesson:    n,
			})
		}

	}

	// –û—Ç—Å–µ–∏–≤–∞–µ–º –ø–æ—Å–ª–µ–¥–Ω–∏–µ –ø–∞—Ä—ã –¥–Ω—è
	last := ssauparser.Diff(completed, next)

	for _, l := range last {
		var nextLesson database.Lesson
		if _, err := db.
			Where(
				"groupid = ? and begin > ?",
				l.GroupId, l.Begin.Format("2006-01-02 15:04:05"),
			).
			Asc("begin").
			Get(&nextLesson); err != nil {
			return nil, err
		}
		// –†–∞–∑–¥–µ–ª—è–µ–º, –∫–∞–∫–∏–µ –ø–∞—Ä—ã –Ω–∞ —ç—Ç–æ–π –Ω–µ–¥–µ–ª–µ, –∫–∞–∫–∏–µ –Ω–∞ —Å–ª–µ–¥—É—é—â–µ–π

		_, nlWeek := nextLesson.Begin.ISOWeek()
		_, nowWeek := now.ISOWeek()
		note := api.Notify{
			IsGroup:   true,
			SheduleID: nextLesson.GroupId,
			Lesson:    nextLesson,
		}
		if nlWeek == nowWeek {
			note.NoteType = api.NextDay
		} else {
			note.NoteType = api.NextWeek
		}
		if !slices.Contains(notify, note) {
			notify = append(notify, note)
		}

	}

	return notify, nil
}

// –¢–µ–∫—Å—Ç —É–≤–µ–¥–æ–º–ª–µ–Ω–∏—è –æ —Å–ª–µ–¥—É—é—â–µ–π –ø–∞—Ä–µ
func StrNext(db *xorm.Engine, note api.Notify) (string, error) {
	// TODO: –ø–µ—Ä–µ—Å–∫–∞–∫–∏–≤–∞—Ç—å –æ–∫–Ω–∞
	// –ü–æ–¥–∫–∞—á–∏–≤–∞–µ–º –≥—Ä—É–ø–ø—ã –∏ –ø–æ–¥–≥—Ä—É–ø–ø—ã
	var pair []database.Lesson
	if !note.IsGroup {
		query := database.Lesson{
			Begin:     note.Lesson.Begin,
			TeacherId: note.SheduleID,
		}
		if err := db.Find(&pair, query); err != nil {
			return "", err
		}
	} else {
		pair = append(pair, note.Lesson)
	}

	str := "–°–µ–π—á–∞—Å –±—É–¥–µ—Ç:\n\n"
	strPair, err := tg.PairToStr(pair, db, note.IsGroup)
	if err != nil {
		return "", err
	}
	str += strPair

	return str, nil
}

// –¢–µ–∫—Å—Ç —É–≤–µ–¥–æ–º–ª–µ–Ω–∏—è –æ —Å–ª–µ–¥—É—é—â–µ–º –¥–Ω–µ
func StrNextDay(bot *tg.Bot, note api.Notify) (string, error) {
	begin := note.Lesson.Begin
	day := time.Date(begin.Year(), begin.Month(), begin.Day(), 0, 0, 0, 0, begin.Location())
	shedule := database.Schedule{
		IsGroup:    true,
		ScheduleID: note.Lesson.GroupId,
	}
	lessons, err := api.GetDayLessons(bot.DB, shedule, day)
	if err != nil {
		return "", err
	}
	if len(lessons) != 0 {
		pairs := api.GroupPairs(lessons)
		dayStr, err := bot.StrDayShedule(pairs, shedule.IsGroup)
		if err != nil {
			return "", err
		}
		str := "–°–µ–≥–æ–¥–Ω—è –±–æ–ª—å—à–µ –Ω–∏—á–µ–≥–æ –Ω–µ—Ç\n"
		str += "–°–ª–µ–¥—É—é—â–∏–µ –∑–∞–Ω—è—Ç–∏—è –≤ " + tg.DayStr(day) + ":\n\n" + dayStr

		return str, nil
	}

	return "", nil
}

// –†–∞—Å—Å—ã–ª–∫–∞ –≤—Å–µ—Ö —É–≤–µ–¥–æ–º–ª–µ–Ω–∏–π
func Mailing(bot *tg.Bot, notes []api.Notify) {
	var ids []int64
	for _, note := range notes {
		if note.SheduleID == 0 {
			continue
		}

		var txt string
		var err error
		var tempTime time.Time
		switch note.NoteType {
		case api.NextLesson:
			txt, err = StrNext(bot.DB, note)
			tempTime = note.Lesson.Begin.Add(80 * time.Minute)
		case api.NextDay:
			txt, err = StrNextDay(bot, note)
		}
		if err != nil {
			log.Println(err)
		}
		// TODO: –ø—Ä–æ—Ä–∞–±–æ—Ç–∞—Ç—å —Ä–∞–∑–Ω—ã–µ –ø–æ–¥–≥—Ä—É–ø–ø—ã
		users, err := api.GetUserForNote(bot.DB, note)
		if err != nil {
			log.Println(err)
		}
		for i, user := range users {
			if slices.Contains(ids, user.TgId) {
				continue
			}
			if note.NoteType != api.NextWeek {
				m, err := bot.SendMsg(&users[i], txt, nil)
				if err != nil {
					bot.CheckBlocked(err, user)
				} else {
					if note.NoteType == api.NextDay {
						getNextDayTemp(user, bot, &tempTime, note)
					}
					AddTemp(m, tempTime, bot)
				}
			} else {
				if err := sendNextWeek(bot, note, &users[i]); err != nil {
					log.Println(err)

					continue
				}
			}
			ids = append(ids, user.TgId)

		}
	}
}

// –†–∞—Å—Å—ã–ª–∫–∞ —É–≤–µ–¥–æ–º–ª–µ–Ω–∏–π –æ —Å–ª–µ–¥—É—é—â–µ–π –Ω–µ–¥–µ–ª–µ
func sendNextWeek(bot *tg.Bot, note api.Notify, user *database.TgUser) error {
	if note.Lesson.Begin.IsZero() {
		return fmt.Errorf("null lesson")
	}
	sh := database.Schedule{
		TgUser:     user,
		IsPersonal: true,
	}
	_, err := bot.GetWeekSummary(
		note.Lesson.Begin,
		sh,
		-1,
		"–ù–∞ —ç—Ç–æ–π –Ω–µ–¥–µ–ª–µ –±–æ–ª—å—à–µ –Ω–∏—á–µ–≥–æ –Ω–µ—Ç\n\n–ù–∞ —Ñ–æ—Ç–æ —Ä–∞—Å–ø–∏—Å–∞–Ω–∏–µ –Ω–∞ —Å–ª–µ–¥—É—é—â—É—é –Ω–µ–¥–µ–ª—é",
	)

	return err
}

// –ü–æ–ª—É—á–∏—Ç—å –≤—Ä–µ–º—è —É–¥–∞–ª–µ–Ω–∏—è —É–≤–µ–¥–æ–º–ª–µ–Ω–∏—è –æ —Å–ª–µ–¥—É—é—â–µ–º –¥–Ω–µ
func getNextDayTemp(user database.TgUser, bot *tg.Bot, tempTime *time.Time, note api.Notify) {
	shInfo := database.ShedulesInUser{
		L9Id: user.L9Id,
	}
	_, err := bot.DB.Get(&shInfo)
	if err != nil {
		bot.Debug.Println(err)

		return
	}
	dt := -1 * shInfo.FirstTime
	*tempTime = note.Lesson.Begin.Add(time.Duration(dt) * time.Minute)
}

// –î–æ–±–∞–≤–∏—Ç—å —Å–æ–æ–±—â–µ–Ω–∏–µ –≤ —Å–ø–∏—Å–æ–∫ –≤—Ä–µ–º–µ–Ω–Ω—ã—Ö
func AddTemp(m tgbotapi.Message, tempTime time.Time, bot *tg.Bot) {
	temp := database.TempMsg{
		TgId:      m.Chat.ID,
		MessageId: m.MessageID,
		Destroy:   tempTime,
	}
	if _, err := bot.DB.InsertOne(temp); err != nil {
		log.Println(err)
	}
}

// –£–¥–∞–ª–µ–Ω–∏–µ –≤—Ä–µ–º–µ–Ω–Ω—ã—Ö —Å–æ–æ–±—â–µ–Ω–∏–π
func ClearTemp(bot *tg.Bot, now time.Time) {
	temp, err := api.GetExpiredNotifies(bot.DB, now)
	HandleErr(err)
	for i, msg := range temp {
		del := tgbotapi.NewDeleteMessage(msg.TgId, msg.MessageId)
		_, err := bot.TG.Request(del)
		HandleErr(err)

		_, err = bot.DB.Delete(&temp[i])
		HandleErr(err)
	}
}

// –†–∞—Å—Å—ã–ª–∫–∞ —Å–æ–æ–±—â–µ–Ω–∏–π –æ –Ω–∞—á–∞–ª–µ –∑–∞–Ω—è—Ç–∏–π
func FirstMailing(bot *tg.Bot, now time.Time) {
	res, err := api.GetFirstLessonNote(bot.DB, now)
	if err != nil {
		log.Println(err)

		return
	}
	for _, r := range res {
		lesson, err := api.GetLesson(bot.DB, r.LessonID)
		if err != nil {
			log.Println(err)

			return
		}
		var str string
		if now.Hour() >= 16 {
			str = "–î–æ–±—Ä—ã–π –≤–µ—á–µ—Ä üåÜ\n"
		} else if now.Hour() >= 11 {
			str = "–î–æ–±—Ä—ã–π –¥–µ–Ω—å üåû\n"
		} else {
			str = "–î–æ–±—Ä–æ–µ —É—Ç—Ä–æ üåÖ\n"
		}
		str += fmt.Sprintf("–ß–µ—Ä–µ–∑ %s –º–∏–Ω—É—Ç –Ω–∞—á–Ω—É—Ç—Å—è –∑–∞–Ω—è—Ç–∏—è\n\n–ü–µ—Ä–≤–∞—è –ø–∞—Ä–∞:\n", r.Time)
		pair, err := tg.PairToStr([]database.Lesson{lesson}, bot.DB, true)
		if err != nil {
			log.Println(err)
		}
		str += pair
		mail := tgbotapi.NewMessage(r.TgID, str)
		msg, err := bot.TG.Send(mail)
		if err != nil {
			log.Println(err)

			continue
		}
		AddTemp(msg, lesson.Begin.Add(15*time.Minute), bot)
	}
}

// –õ–æ–≥–∏—Ä–æ–≤–∞–Ω–∏–µ –Ω–µ–∫—Ä–∏—Ç–∏—á–µ—Å–∫–∏—Ö –æ—à–∏–±–æ–∫
func HandleErr(err error) {
	if err != nil {
		log.Println(err)
	}
}
