package hooks

import (
	"errors"
	"net/http"
	"os"
	"strconv"
	"strings"

	"git.smarteching.com/goffee/core"
	"git.smarteching.com/jacs/goffeetabler/models"
	"git.smarteching.com/jacs/goffeetabler/utils"
	"gorm.io/gorm"
)

var CheckSessionCookie core.Hook = func(c *core.Context) {

	pass := true
	token := ""
	usercookie, err := c.GetCookie()
	if err != nil {

	}
	token = usercookie.Token
	if token == "" {
		pass = false
	} else {
		payload, err := c.GetJWT().DecodeToken(token)
		if err != nil {
			pass = false
		} else {

			userAgent := c.GetUserAgent()
			hashedCacheKey := utils.CreateAuthTokenHashedCacheKey(uint(c.CastToInt(payload["userID"])), userAgent)

			cachedToken, err := c.GetCache().Get(hashedCacheKey)
			if err != nil {
				pass = false
			} else if cachedToken != token {
				pass = false
			} else {
				var user models.User
				res := c.GetGorm().Where("id = ?", payload["userID"]).First(&user)
				if res.Error != nil && !errors.Is(res.Error, gorm.ErrRecordNotFound) {
					pass = false
				}
			}
		}
	}
	// if have session redirect protected page
	if pass {
		c.Response.Redirect("/appsample").ForceSendResponse()
		return
	}

	c.Next()

}

var AuthCheck core.Hook = func(c *core.Context) {

	// check if template engine is enable
	TemplateEnableStr := os.Getenv("TEMPLATE_ENABLE")
	if TemplateEnableStr == "" {
		TemplateEnableStr = "false"
	}
	TemplateEnable, _ := strconv.ParseBool(TemplateEnableStr)

	token := ""

	if TemplateEnable {
		usercookie, err := c.GetCookie()
		if err != nil {

		}
		token = usercookie.Token
		if token == "" {
			c.Response.Redirect("/applogin").ForceSendResponse()
			return
		}

	} else {
		tokenRaw := c.GetHeader("Authorization")
		token = strings.TrimSpace(strings.Replace(tokenRaw, "Bearer", "", 1))
		if token == "" {
			c.Response.SetStatusCode(http.StatusUnauthorized).Json(c.MapToJson(map[string]interface{}{
				"message": "unauthorized",
			})).ForceSendResponse()
			return
		}
	}

	payload, err := c.GetJWT().DecodeToken(token)
	if err != nil {
		if TemplateEnable {
			c.Response.Redirect("/applogin").ForceSendResponse()
		} else {
			c.Response.SetStatusCode(http.StatusUnauthorized).Json(c.MapToJson(map[string]interface{}{
				"message": "unauthorized",
			})).ForceSendResponse()
		}
		return
	}
	userAgent := c.GetUserAgent()
	hashedCacheKey := utils.CreateAuthTokenHashedCacheKey(uint(c.CastToInt(payload["userID"])), userAgent)

	cachedToken, err := c.GetCache().Get(hashedCacheKey)
	if err != nil {
		// user signed out
		if TemplateEnable {
			c.Response.Redirect("/applogin").ForceSendResponse()
		} else {
			c.Response.SetStatusCode(http.StatusUnauthorized).Json(c.MapToJson(map[string]interface{}{
				"message": "unauthorized",
			})).ForceSendResponse()
		}
		return
	}
	if cachedToken != token {
		// using old token replaced with new one after recent signin
		if TemplateEnable {
			c.Response.Redirect("/applogin").ForceSendResponse()
		} else {
			c.Response.SetStatusCode(http.StatusUnauthorized).Json(c.MapToJson(map[string]interface{}{
				"message": "unauthorized",
			})).ForceSendResponse()
		}
		return
	}

	var user models.User
	res := c.GetGorm().Where("id = ?", payload["userID"]).First(&user)
	if res.Error != nil && !errors.Is(res.Error, gorm.ErrRecordNotFound) {
		// error with the database
		c.GetLogger().Error(res.Error.Error())
		if TemplateEnable {
			c.Response.Redirect("/applogin").ForceSendResponse()
		} else {
			c.Response.SetStatusCode(http.StatusInternalServerError).Json(c.MapToJson(map[string]interface{}{
				"message": "internal error",
			})).ForceSendResponse()
		}
		return
	}

	c.Next()
}
