package api

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	"path"
	"strconv"

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

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

func declareEventsRoutes(router *gin.RouterGroup) {
	router.GET("/events", getEvents)
	router.GET("/events.json", getLastEvents)
	router.POST("/events", newEvent)
	router.DELETE("/events", clearEvents)

	apiEventsRoutes := router.Group("/events/:evid")
	apiEventsRoutes.Use(EventHandler)
	apiEventsRoutes.GET("", showEvent)
	apiEventsRoutes.PUT("", updateEvent)
	apiEventsRoutes.DELETE("", deleteEvent)
}

func EventHandler(c *gin.Context) {
	evid, err := strconv.ParseInt(string(c.Params.ByName("evid")), 10, 64)
	if err != nil {
		c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": "Invalid event identifier"})
		return
	}

	event, err := fic.GetEvent(evid)
	if err != nil {
		c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"errmsg": "Event not found"})
		return
	}

	c.Set("event", event)

	c.Next()
}

func genEventsFile() error {
	if evts, err := fic.GetLastEvents(); err != nil {
		return err
	} else if j, err := json.Marshal(evts); err != nil {
		return err
	} else if err := ioutil.WriteFile(path.Join(TeamsDir, "events.json"), j, 0666); err != nil {
		return err
	}

	return nil
}

func getEvents(c *gin.Context) {
	evts, err := fic.GetEvents()
	if err != nil {
		log.Println("Unable to GetEvents:", err.Error())
		c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "Unable to retrieve events list"})
		return
	}

	c.JSON(http.StatusOK, evts)
}

func getLastEvents(c *gin.Context) {
	evts, err := fic.GetLastEvents()

	if err != nil {
		log.Println("Unable to GetLastEvents:", err.Error())
		c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "Unable to retrieve last events list"})
		return
	}

	c.JSON(http.StatusOK, evts)
}

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

	event, err := fic.NewEvent(ue.Text, ue.Kind)
	if err != nil {
		log.Printf("Unable to newEvent: %s", err.Error())
		c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "An error occurs during event creation."})
		return
	}

	genEventsFile()

	c.JSON(http.StatusOK, event)
}

func clearEvents(c *gin.Context) {
	nb, err := fic.ClearEvents()
	if err != nil {
		log.Printf("Unable to clearEvent: %s", err.Error())
		c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "An error occurs during event clearing."})
		return
	}

	c.JSON(http.StatusOK, nb)
}

func showEvent(c *gin.Context) {
	event := c.MustGet("event").(*fic.Event)
	c.JSON(http.StatusOK, event)
}

func updateEvent(c *gin.Context) {
	event := c.MustGet("event").(*fic.Event)

	var ue fic.Event
	err := c.ShouldBindJSON(&ue)
	if err != nil {
		c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()})
		return
	}

	ue.Id = event.Id

	if _, err := ue.Update(); err != nil {
		log.Printf("Unable to updateEvent: %s", err.Error())
		c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "An error occurs during event update."})
		return
	}

	genEventsFile()

	c.JSON(http.StatusOK, ue)
}

func deleteEvent(c *gin.Context) {
	event := c.MustGet("event").(*fic.Event)

	_, err := event.Delete()
	if err != nil {
		log.Printf("Unable to deleteEvent: %s", err.Error())
		c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "An error occurs during event deletion."})
		return
	}

	genEventsFile()

	c.JSON(http.StatusOK, true)
}
