package executor

import (
	"context"
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"
	"strconv"
	"time"
)

type jsonBody struct {
	Ids []int64
}

type PoolAPI struct {
	pool *TaskPool
	addr string
	server *http.Server
}

func NewPoolAPI(p *TaskPool, addr string) *PoolAPI {
	return &PoolAPI{
		pool: p,
		addr: addr,
	}
}

func (self *PoolAPI) Start() {
	r := gin.Default()
	r.GET("/", self.do_homepage())
	r.POST("/v1/pool/add", self.do_pool_add())
	r.POST("/v1/pool/query", self.do_pool_query())
	r.POST("/v1/pool/remove", self.do_pool_remove())
	r.POST("/v1/pool/pause", self.do_pool_pause())
	r.POST("/v1/pool/resume", self.do_pool_resume())

	self.server = &http.Server{
		Addr:    self.addr,
		Handler: r,
	}

	go func() {
		if err := self.server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			panic("listen error " + err.Error())
		}
	}()
}

func (self *PoolAPI) Stop() {
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	if err := self.server.Shutdown(ctx); err != nil {
		fmt.Println("Server shutdown error:", err)
	}
	select {
	case <-ctx.Done():
		fmt.Println("Timeout and quit")
	}
}

func (self *PoolAPI) do_homepage() gin.HandlerFunc {
	return func(c *gin.Context) {
		c.String(http.StatusOK, "Welcome to executor %v", version)
	}
}

func (self *PoolAPI) do_pool_add() gin.HandlerFunc {
	return func(c *gin.Context) {
		task_conf := &TaskConf{}
		err := c.BindJSON(task_conf)
		if err != nil {
			c.AbortWithStatus(http.StatusBadRequest)
			return
		}
		task := NewTask(task_conf)
		err = self.pool.AddTask(task)
		if err != nil {
			c.JSON(http.StatusOK, gin.H{
				"ec": -3,
			})
			return
		}
		c.JSON(http.StatusOK, gin.H{
			"ec": 0,
			"id": task.Id,
		})
	}
}

func (self *PoolAPI) do_pool_query() gin.HandlerFunc {
	return func(c *gin.Context) {
		tasks := self.pool.Tasks()
		res := make(gin.H)
		for id, t := range tasks {
			res[strconv.FormatInt(id, 10)] = t
		}
		c.JSON(http.StatusOK, res)
	}
}

func (self *PoolAPI) do_pool_remove() gin.HandlerFunc {
	return func(c *gin.Context) {
		jb := &jsonBody{}
		err := c.BindJSON(jb)
		if err != nil {
			c.AbortWithStatus(http.StatusBadRequest)
			return
		}

		self.pool.RemoveTasks(jb.Ids...)
		c.JSON(http.StatusOK, gin.H{"ec": 0})
	}
}

func (self *PoolAPI) do_pool_pause() gin.HandlerFunc {
	return func(c *gin.Context) {
		jb := &jsonBody{}
		err := c.BindJSON(jb)
		if err != nil {
			c.AbortWithStatus(http.StatusBadRequest)
			return
		}

		self.pool.PauseTasks(jb.Ids...)
		c.JSON(http.StatusOK, gin.H{"ec": 0})
	}
}

func (self *PoolAPI) do_pool_resume() gin.HandlerFunc {
	return func(c *gin.Context) {
		jb := &jsonBody{}
		err := c.BindJSON(jb)
		if err != nil {
			c.AbortWithStatus(http.StatusBadRequest)
			return
		}

		self.pool.ResumeTasks(jb.Ids...)
		c.JSON(http.StatusOK, gin.H{"ec": 0})
	}
}
