package db

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"olympus/oncall/backend/pkg/log"
	"os"

	"gopkg.in/yaml.v2"
)

func DeleteOnePerson(engineerId int, categoryId int) error {
	categoryInf, err := GetCategoryInfo(categoryId)
	if err != nil {
		return err
	}
	tempWeek, err := GetTempWeekId()
	if err != nil {
		return err
	}
	// delete from the list where the person in this round.
	nextRound := categoryInf.NextRound
	const SCHEDULE_IN_THIS_ROUND = `
		select
			week_id
		from
			shift
		where
			engineer_id = ?
			and week_id >= ?
			and week_id < ?
			and category_id = ?
		limit 1`
	for {
		var weekId float32
		resSql := GetDB().Raw(SCHEDULE_IN_THIS_ROUND, engineerId, tempWeek, nextRound, categoryId).Scan(&weekId)
		if resSql.Error != nil {
			log.Error("msg", "error: find the engineer in this round", "error info", err)
			break
		}
		if weekId != 0 {
			const DELETE_ONE_FROM_SHIFT = `
				delete from
					shift
				where
					week_id = ?
					and engineer_id = ?
					and category_id = ?`
			GetDB().Exec(DELETE_ONE_FROM_SHIFT, weekId, engineerId, categoryId)
			const DECREASE_SHIFT_WEEK_BY_ONE = `
			update
				shift
			set
				week_id = week_id -1
			where
				week_id > ?
				and category_id = ?`
			GetDB().Exec(DECREASE_SHIFT_WEEK_BY_ONE, weekId, categoryId)
			nextRound--
		} else {
			break
		}
	}
	// set new next round.
	const SET_NEXT_ROUND = `
		update
			categories
		set
			next_round = ?
		where
			category_id = ?`
	GetDB().Exec(SET_NEXT_ROUND, nextRound, categoryId)
	// // delete from next round.
	// const DELETE_ONE_FROM_NEXT_ROUND = `
	// delete from
	// 	shift
	// where
	// 	week_id >= ?
	// 	and engineer_id = ?
	// 	and category_id = ?
	// `
	// GetDB().Exec(DELETE_ONE_FROM_NEXT_ROUND, nextRound, engineerId, categoryId)
	// set available to 0
	const DELETE_ONE_ENGINEER = `
		update
			engineers
		set
			available = 0
		where
			engineer_id = ?`
	GetDB().Exec(DELETE_ONE_ENGINEER, engineerId)

	DeleteRound(engineerId, categoryId)

	// generate the next round schedule.
	GenerateNextRoundByConfig(categoryId)

	return nil
}

func DeleteRound(engineerId int, categoryId int) {
	content, err := ioutil.ReadFile("./etc/round.yml")
	if err != nil {
		log.Error("msg", "fail to load round file")
	}
	round := &Round{}

	err = yaml.Unmarshal(content, round)
	if err != nil {
		log.Error("msg", "fail to unmarshal round file")
	}
	newShifts := make([]*Shift, 0)
	for _, robin := range round.Shifts {
		newRobin := make([][]int, 0)
		if robin.Category == categoryId {
			for _, oncallers := range robin.Robin {
				if !IsContainInt(oncallers, engineerId) {
					newRobin = append(newRobin, oncallers)
				} else {
					fmt.Println("find")
				}
			}
		} else {
			newRobin = append(newRobin, robin.Robin...)
		}
		newShifts = append(newShifts, &Shift{Category: robin.Category, Robin: newRobin})
	}
	round.Shifts = newShifts
	marsheledRound, err := yaml.Marshal(round)
	if err != nil {
		log.Error("msg", "marshal the round info")
		return
	}
	filePath := "./etc/round.yml"
	file, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
	if err != nil {
		log.Error("msg", "open round config file")
		return
	}
	defer file.Close()
	write := bufio.NewWriter(file)
	write.Write(marsheledRound)
	write.Flush()
}

func IsContainInt(items []int, item int) bool {
	for _, eachItem := range items {
		if eachItem == item {
			return true
		}
	}
	return false
}
