package db

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

	"gopkg.in/yaml.v2"
)

func AddOnePerson(name string, enName string, email string, phone string, categoryId int, teamId int) error {
	const SELECT_ENGINEER = `
		select
			engineer_name
		from
			engineers
		where
			email = ?
			and team_id = ?
		limit
			1`
	var selected string
	sqlRes := GetDB().Raw(SELECT_ENGINEER, email, teamId).Scan(&selected)
	if sqlRes.Error != nil {
		log.Error("msg", "error: select engineer", "error info", sqlRes.Error)
		return sqlRes.Error
	}
	if selected == "" {
		const ADD_ONE_TO_ENGINEER = `
		insert into
			engineers (
				engineer_name,
				team_id,
				contribution,
				available,
				engineer_en_name,
				email,
				experience
			)
		values
			(?, ?, 0, 1, ?, ?, 0)`
		GetDB().Exec(ADD_ONE_TO_ENGINEER, name, teamId, enName, email)
		GetDB().Exec("set sql_safe_updates = 0")
		const ADD_PHONE_TO_ENGINEER = `
		update
			engineers
		set
			phone_number = aes_encrypt(
				cast(? as char charset binary),
				'pingcap',
				'dfsdexfe8eidndft'
			)
		where
			engineer_name = ?`
		GetDB().Exec(ADD_PHONE_TO_ENGINEER, phone, name)
		const INITIAL_CONTRIBUTION = `
		update
			engineers
		set
			contribution = (
				select
					min(t2.contribution)
				from
					(
						select
							engineer_name,
							contribution
						from
							engineers as e1
							join teams on e1.team_id = teams.team_id
						where
							teams.category_id = ?
							and available = 1
					) as t2
			)
		where
			engineer_name = ?`
		GetDB().Exec(INITIAL_CONTRIBUTION, categoryId, name)
	} else {
		// update the team
		const UPDATE_TEAM_FOR_ENGINEER = `
		update
			engineers
		set
			available = 1
		where
			email = ?
			and team_id = ?`
		GetDB().Exec(UPDATE_TEAM_FOR_ENGINEER, email, teamId)
	}
	const FIND_ENGINEER_BY_EMAIL_AND_TEAM = `
		select
			engineer_id
		from 
			engineers
		where 
			email = ?
			and team_id = ?
	`
	var engineerId int
	GetDB().Raw(FIND_ENGINEER_BY_EMAIL_AND_TEAM, email, teamId).Scan(&engineerId)
	AddRound(engineerId, categoryId)
	GenerateNextRoundByConfig(categoryId)
	return nil
}

func AddRound(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)
		newRobin = append(newRobin, robin.Robin...)
		if robin.Category == categoryId {
			lastRound := make([]int, 0)
			lastRound = append(lastRound, engineerId)
			newRobin = append(newRobin, lastRound)
		}
		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()
}
