package api

import (
	"net/http"
	"strconv"

	"srs.epita.fr/fic-server/libfic"

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

func declareTodoRoutes(router *gin.RouterGroup) {
	router.GET("/qa_exercices.json", getExerciceTested)
	router.GET("/qa_mywork.json", getQAWork)
	router.GET("/qa_myexercices.json", getQAView)
	router.GET("/qa_work.json", getQATodo)
}

func declareTodoManagerRoutes(router *gin.RouterGroup) {
	router.POST("/qa_my_exercices.json", addQAView)
	router.POST("/qa_work.json", createQATodo)

	todosRoutes := router.Group("/todo/:wid")
	todosRoutes.Use(todoHandler)
	todosRoutes.GET("", showTodo)
	todosRoutes.DELETE("", deleteQATodo)
}

type exerciceTested map[int64]string

func getExerciceTested(c *gin.Context) {
	var teamid int64
	if team, ok := c.Get("team"); ok {
		teamid = team.(*fic.Team).Id
	} else {
		teamid = c.MustGet("LoggedTeam").(int64)
	}

	team, err := fic.GetTeam(teamid)
	if err != nil {
		c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()})
		return
	}

	exercices, err := fic.GetExercices()
	if err != nil {
		c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()})
		return
	}

	ret := exerciceTested{}

	for _, exercice := range exercices {
		if team.HasAccess(exercice) {
			if t := team.HasSolved(exercice); t != nil {
				ret[exercice.Id] = "solved"
			} else if cnt, _ := team.CountTries(exercice); cnt > 0 {
				ret[exercice.Id] = "tried"
			} else {
				ret[exercice.Id] = "access"
			}
		}
	}

	c.JSON(http.StatusOK, ret)
}

func getQAView(c *gin.Context) {
	var teamid int64
	if team, ok := c.Get("team"); ok {
		teamid = team.(*fic.Team).Id
	} else {
		teamid = c.MustGet("LoggedTeam").(int64)
	}

	team, err := fic.GetTeam(teamid)
	if err != nil {
		c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()})
		return
	}

	view, err := team.GetQAView()
	if err != nil {
		c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()})
		return
	}

	c.JSON(http.StatusOK, view)
}

func getQAWork(c *gin.Context) {
	var teamid int64
	if team, ok := c.Get("team"); ok {
		teamid = team.(*fic.Team).Id
	} else {
		teamid = c.MustGet("LoggedTeam").(int64)
	}

	team, err := fic.GetTeam(teamid)
	if err != nil {
		c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()})
		return
	}

	queries, err := team.GetQAQueries()
	if err != nil {
		c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()})
		return
	}

	c.JSON(http.StatusOK, queries)
}

func getQATodo(c *gin.Context) {
	var teamid int64
	if team, ok := c.Get("team"); ok {
		teamid = team.(*fic.Team).Id
	} else {
		teamid = c.MustGet("LoggedTeam").(int64)
	}

	team, err := fic.GetTeam(teamid)
	if err != nil {
		c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()})
		return
	}

	todo, err := team.GetQATodo()
	if err != nil {
		c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()})
		return
	}

	exercices, err := fic.GetExercices()
	if err != nil {
		c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()})
		return
	}

	for _, exercice := range exercices {
		if cnt, _ := team.CountTries(exercice); cnt > 0 {
			todo = append(todo, &fic.QATodo{
				Id:         0,
				IdTeam:     teamid,
				IdExercice: exercice.Id,
			})
		}
	}

	c.JSON(http.StatusOK, todo)
}

func createQATodo(c *gin.Context) {
	var ut fic.QATodo
	if err := c.ShouldBindJSON(&ut); err != nil {
		c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()})
		return
	}

	team, err := fic.GetTeam(ut.IdTeam)
	if err != nil {
		c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()})
		return
	}

	todo, err := team.NewQATodo(ut.IdExercice)
	if err != nil {
		c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()})
		return
	}

	c.JSON(http.StatusOK, todo)
}

func addQAView(c *gin.Context) {
	var ut fic.QATodo
	if err := c.ShouldBindJSON(&ut); err != nil {
		c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()})
		return
	}

	team, err := fic.GetTeam(ut.IdTeam)
	if err != nil {
		c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()})
		return
	}

	view, err := team.NewQAView(ut.IdExercice)
	if err != nil {
		c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()})
		return
	}

	c.JSON(http.StatusOK, view)
}

func todoHandler(c *gin.Context) {
	team := c.MustGet("team").(*fic.Team)

	var wid int64
	var todos []*fic.QATodo
	var err error

	if wid, err = strconv.ParseInt(string(c.Param("wid")), 10, 64); err != nil {
		c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": "Bad todo identifier."})
		return
	}

	if todos, err = team.GetQATodo(); err != nil {
		c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"errmsg": "Todo not found."})
		return
	}

	for _, t := range todos {
		if t.Id == wid {
			c.Set("todo", t)
			c.Next()
			return
		}
	}

	c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"errmsg": "Unable to find the requested QA Todo"})
}

func showTodo(c *gin.Context) {
	c.JSON(http.StatusOK, c.MustGet("todo"))
}

func deleteQATodo(c *gin.Context) {
	todo := c.MustGet("todo").(*fic.QATodo)

	if _, err := todo.Delete(); err != nil {
		c.AbortWithError(http.StatusInternalServerError, err)
	} else {
		c.Status(http.StatusOK)
	}
}
