package scheduler

import (
	"encoding/json"
	"fmt"
	"olympus/oncall/backend/db"
	"olympus/oncall/backend/model"
	"olympus/oncall/backend/pkg/log"
	"strconv"

	"github.com/gin-gonic/gin"
)

type Scheduler struct {
}

func New(r *gin.RouterGroup) (*Scheduler, error) {
	s := &Scheduler{}
	r.GET("/shiftview", s.shiftviewHandler())
	r.GET("/categoryById", s.categoryHandler())
	r.GET("/delete", s.deleteHandler())
	r.GET("/change", s.changeHandler())
	r.GET("/add", s.addHandler())
	r.GET("/current", s.currentHandler())
	return s, nil
}

func (s *Scheduler) shiftviewHandler() func(*gin.Context) {
	return func(ctx *gin.Context) {
		db.MayUpdateNextRound()
		tData := &model.TemplateData{}
		overview, start, end, err := db.GetCurrentOverview()
		if err != nil {
			return
		}
		tData.ShiftOverview = *overview
		tData.StartDate = start
		tData.EndDate = end

		shiftList, err := db.GetShiftList()
		if err != nil {
			return
		}
		tData.ShiftList = shiftList

		ip := ctx.Request.URL
		log.Info("msg", "receive a request to view schedule", "ip", ip.Host)
		jsonString, err := json.Marshal(tData)
		if err != nil {
			log.Error("msg", "error: unmarshal the template data", "error info", err)
		}
		ctx.Writer.Write(jsonString)
	}
}

func (s *Scheduler) categoryHandler() func(*gin.Context) {
	return func(ctx *gin.Context) {
		ip := ctx.Request.URL
		log.Info("msg", "receive a request to view category", "ip", ip.Host)
		categoryId := ctx.Query("id")
		categoryId64, err := strconv.ParseInt(categoryId, 10, 32)
		if err != nil {
			log.Error("msg", "error: parse int", "ctx info", categoryId, "error info", err)
		}
		categoryIdInt := int(categoryId64)
		tCatagory := &model.CategoryPage{}
		tCatagory.CategoryId = categoryIdInt
		shiftList, err := db.GetCategoryShiftList(categoryIdInt)
		if err != nil {
			log.Error("msg", "error: get shift list for category", "category id", categoryId, "error info", err)
		}
		tCatagory.ShiftList = *shiftList
		robin, err := db.GetRobin(categoryIdInt)
		if err != nil {
			log.Error("msg", "error: get robin for category", "category id", categoryId, "error info", err)
		}
		tCatagory.Robin = robin
		availables, err := db.GetAvailableRolesInCategory(categoryIdInt)
		if err != nil {
			log.Error("msg", "error: get availables for category", "category id", categoryId, "error info", err)
		}
		tCatagory.Availables = availables
		teams, err := db.GetTeams(categoryIdInt)
		if err != nil {
			log.Error("msg", "error: get teams for category", "category id", categoryId, "error info", err)
		}
		tCatagory.Teams = teams

		jsonString, _ := json.Marshal(tCatagory)
		ctx.Writer.Write(jsonString)
	}
}

func (s *Scheduler) deleteHandler() func(ctx *gin.Context) {
	return func(ctx *gin.Context) {
		ip := ctx.Request.URL
		log.Info("msg", "receive a request to delete", "ip", ip.Host)
		categoryId := ctx.Query("category_id")
		categoryId64, err := strconv.ParseInt(categoryId, 10, 32)
		if err != nil {
			log.Error("msg", "error: parse int", "ctx info", categoryId, "error info", err)
		}
		categoryIdInt := int(categoryId64)

		engineerId := ctx.Query("engineer_id")
		engineerId64, err := strconv.ParseInt(engineerId, 10, 32)
		if err != nil {
			log.Error("msg", "error: parse int", "ctx info", engineerId, "error info", err)
		}
		engineerIdInt := int(engineerId64)

		db.DeleteOnePerson(engineerIdInt, categoryIdInt)
		log.Info("msg", "receive a request to delete", "engineer id", engineerIdInt, "category id", categoryId)

		ctx.Writer.Write([]byte("successful delete"))
	}
}

func (s *Scheduler) addHandler() func(ctx *gin.Context) {
	return func(ctx *gin.Context) {
		ip := ctx.Request.URL
		log.Info("msg", "receive a request to add", "ip", ip.Host)
		name := ctx.Query("name")
		enName := ctx.Query("en_name")
		email := ctx.Query("email")
		phone := ctx.Query("phone")
		categoryId := ctx.Query("category_id")
		categoryId64, err := strconv.ParseInt(categoryId, 10, 32)
		if err != nil {
			log.Error("msg", "error: parse int", "ctx info", categoryId, "error info", err)
		}
		categoryIdInt := int(categoryId64)
		teamId := ctx.Query("team_id")
		teamId64, err := strconv.ParseInt(teamId, 10, 32)
		if err != nil {
			log.Error("msg", "error: parse int", "ctx info", teamId, "error info", err)
		}
		teamIdInt := int(teamId64)

		db.AddOnePerson(name, enName, email, phone, categoryIdInt, teamIdInt)
		log.Info("msg", "receive a request to add", "engineer name", name, "email", email, "category id", categoryId)

		ctx.Writer.Write([]byte("successful add"))
	}
}

func (s *Scheduler) changeHandler() func(ctx *gin.Context) {
	return func(ctx *gin.Context) {
		ip := ctx.Request.URL
		log.Info("msg", "receive a request to change", "ip", ip.Host)

		categoryId := ctx.Query("category_id")
		categoryId64, err := strconv.ParseInt(categoryId, 10, 32)
		if err != nil {
			log.Error("msg", "error: parse int", "ctx info", categoryId, "error info", err)
		}
		categoryIdInt := int(categoryId64)

		engineerId := ctx.Query("engineer_id")
		engineerId64, err := strconv.ParseInt(engineerId, 10, 32)
		if err != nil {
			log.Error("msg", "error: parse int", "ctx info", engineerId, "error info", err)
		}
		engineerIdInt := int(engineerId64)

		oldId := ctx.Query("old_id")
		oldId64, err := strconv.ParseInt(oldId, 10, 32)
		if err != nil {
			log.Error("msg", "error: parse int", "ctx info", oldId, "error info", err)
		}
		oldIdInt := int(oldId64)

		weekId := ctx.Query("week_id")
		weekId64, err := strconv.ParseFloat(weekId, 32)
		if err != nil {
			log.Error("msg", "error: parse float", "ctx info", weekId, "error info", err)
		}
		// weekIdFloat := float32(weekId64)
		weekIdDecimal2, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", weekId64), 64)

		db.ChangeManually(engineerIdInt, categoryIdInt, weekIdDecimal2, oldIdInt)
		log.Info("msg", "receive a request to change", "old id", oldIdInt, "new id", engineerIdInt, "week id", weekIdDecimal2, "category id", categoryId)
		ctx.Writer.Write([]byte("successfully change"))
	}
}

func (s *Scheduler) currentHandler() func(ctx *gin.Context) {
	return func(ctx *gin.Context) {
		ip := ctx.Request.URL
		log.Info("msg", "receive a request to see current week's schedule", "ip", ip.Host)

		res, err := db.GetCurrentWeekSchedule()
		if err != nil {
			log.Error("msg", "error: get current week oncall schedule", "error info", err)
		}
		jsonString, _ := json.Marshal(res)
		ctx.Writer.Write(jsonString)
	}
}
