package webpage

import (
	"app/database"
	"github.com/gin-contrib/static"
	"github.com/gin-gonic/gin"
	"net/http"
)

func (wp *Webpage) redirectHome(c *gin.Context) {
	c.Redirect(http.StatusTemporaryRedirect, "/view/tasks")
}

func (wp *Webpage) isLoggedInMiddleware(c *gin.Context) bool {
	username := c.Request.Header.Get("username")
	if wp.Database.UserIsLoggedIn(username) {
		return true
	} else {
		c.JSON(401, gin.H{"message": "unauthorized"})
		return false
	}
}

func (wp *Webpage) defineRoutes() {

	view := wp.Router.Group("/view")
	{
		view.GET("/tasks", func(c *gin.Context) {
			c.HTML(http.StatusOK, "tasks.tmpl", gin.H{"title": "Tasks"})
		})
		view.GET("/login", func(c *gin.Context) {
			c.HTML(http.StatusOK, "login.tmpl", gin.H{"title": "Login"})
		})
		view.GET("/register", func(c *gin.Context) {
			c.HTML(http.StatusOK, "register.tmpl", gin.H{"title": "Register"})
		})
	}
	tasks := wp.Router.Group("/tasks")
	{
		tasks.GET("", func(c *gin.Context) {
			if wp.isLoggedInMiddleware(c) {
				username := c.Request.Header.Get("username")
				filter := c.Query("filter")
				if filter != "" {
					// SQL Injection: http://localhost:8080/tasks?filter=' or 1=1--
					tasks := wp.Database.FilteredTasks(username, filter)
					c.JSON(200, gin.H{"tasks": tasks})
					return
				}
				tasks := wp.Database.GetAllTasks(username)
				c.JSON(200, gin.H{"tasks": tasks})
			}
		})
		tasks.POST("", func(c *gin.Context) {
			if wp.isLoggedInMiddleware(c) {
				username := c.Request.Header.Get("username")
				description, existing := c.GetPostForm("description")
				if existing == false || description == "" {
					c.JSON(400, gin.H{"message": "bad post form"})
					return
				}
				task := wp.Database.CreateTask(username, description)
				c.JSON(200, gin.H{"task": task})
			}
		})
		tasks.DELETE("", func(c *gin.Context) {
			if wp.isLoggedInMiddleware(c) {
				id := c.Query("id")
				ok := wp.Database.DeleteTask(id)
				if !ok {
					c.JSON(500, gin.H{"message": "cannot delete task"})
					return
				}
				c.JSON(200, gin.H{"message": "success"})
			}
		})
		tasks.PUT("", func(c *gin.Context) {
			if wp.isLoggedInMiddleware(c) {
				id := c.Query("id")
				done := c.Query("done")
				ok := wp.Database.UpdateTask(id, done)
				if !ok {
					c.JSON(500, gin.H{"message": "cannot update task"})
					return
				}
				c.JSON(200, gin.H{"message": "success"})
			}
		})
	}

	auth := wp.Router.Group("/auth")
	{
		auth.GET("/user", func(c *gin.Context) {
			username := c.Request.Header.Get("username")
			if username != "" {
				success := wp.Database.UserIsLoggedIn(username)
				c.JSON(200, gin.H{"logged_in": success, "username": username})
				return
			}
			c.JSON(200, gin.H{"logged_in": false, "username": ""})
		})
		auth.PUT("/user", func(c *gin.Context) {
			username := c.Query("username")
			password := c.Query("password")
			wp.Database.ChangeUserPassword(username, password)
			c.JSON(200, gin.H{"message": "success"})
		})
		auth.POST("/logout", func(c *gin.Context) {
			username, uExisting := c.GetPostForm("username")
			if uExisting == false || username == "" {
				c.JSON(400, gin.H{"message": "bad post form"})
				return
			}
			success := wp.Database.LogoutUser(username)
			c.JSON(200, gin.H{"logged_out": success, "username": username})
		})
		auth.POST("/login", func(c *gin.Context) {
			username, uExisting := c.GetPostForm("username")
			password, pExisting := c.GetPostForm("password")
			if uExisting == false || pExisting == false || username == "" || password == "" {
				c.JSON(400, gin.H{"message": "no valid post form"})
				return
			}
			success := wp.Database.LoginUser(username, password)
			if success == true {
				c.JSON(200, gin.H{"logged_in": success, "username": username})
				return
			}
			c.JSON(401, gin.H{"message": "user or password not found"})
		})
		auth.POST("/register", func(c *gin.Context) {
			username, uExisting := c.GetPostForm("username")
			password, pExisting := c.GetPostForm("password")
			if uExisting == false || pExisting == false || username == "" || password == "" {
				c.JSON(400, gin.H{"message": "no valid post form"})
				return
			}
			err := wp.Database.CreateUser(username, password)
			if err != nil {
				c.JSON(500, gin.H{"message": err.Error()})
				return
			}
			c.JSON(200, gin.H{"message": "user registered", "username": username})
		})
	}
	wp.Router.NoRoute(func(c *gin.Context) {
		wp.redirectHome(c)
	})
}

func (wp *Webpage) initialize() {
	wp.Database = database.Database{Location: "sqlite.db"}
	wp.Database.Initialize()
}

func (wp *Webpage) Run() {
	wp.initialize()
	wp.Router = gin.New()
	wp.Router.Use(gin.Recovery())
	wp.Router.SetTrustedProxies(nil)
	wp.Router.Use(static.Serve("/static", static.LocalFile("./static", false)))
	wp.Router.LoadHTMLGlob("templates/*")
	wp.defineRoutes()
	wp.Router.Run()
}
