package sess

import (
	"encoding/json"
	"errors"
	"fmt"

	"git.clearsky.net.au/cody/gex.git/sess/jwt"
	"git.clearsky.net.au/cody/gex.git/srv"
	"git.clearsky.net.au/cody/gex.git/utils"

	"time"
)

type Sess struct {
	req     *srv.Req
	res     *srv.Res
	Expires time.Time
	Data    map[string]any
}

// config defaults
var TOKENNAME string = "SessToken"
var TIMEOUT time.Duration = 1 * time.Hour
var SECRET string = "secret"

func (sess *Sess) Construct(req *srv.Req, res *srv.Res) {
	sess.req = req
	sess.res = res

	sess.setDefaults()

	// check cookie is valid and not expired
	cookie, err := req.Cookie(TOKENNAME)

	if err != nil {
		//utils.Err(err)
		return
	}

	// decode jwt to json bytes
	jsonByt, err := jwt.Decode(cookie, SECRET)
	if err != nil {
		utils.Err(err)
		return
	}

	// decode json bytes to session
	err = json.Unmarshal(jsonByt, &sess)
	if err != nil {
		utils.Err(err)
		return
	}

	// if session token has expired, return default session
	if time.Now().After(sess.Expires) {
		if time.Now().After(sess.Expires.Add(TIMEOUT)) {
			sess.Expires = time.Now().Add(20 * time.Minute)
			return
		}
		fmt.Println("session expired")
		sess.setDefaults()
	}

}

func (sess *Sess) setDefaults() {
	sess.Data = make(map[string]any)
	sess.Expires = time.Now().Add(20 * time.Minute)
}

func (sess *Sess) Token() (string, error) {
	jsonStr, err := json.Marshal(sess)
	if err != nil {
		return "", err
	}

	// encode the json to jwt and set the cookie
	token, err := jwt.Encode(jsonStr, SECRET)
	if err != nil {
		return "", err
	}
	return token, nil
}

// Saves token to cookie
func (sess *Sess) Save() {

	// get the session token
	token, err := sess.Token()
	if err != nil {
		sess.res.Send(err.Error())
		return
	}

	// set the token cookie
	sess.res.Cookie(TOKENNAME, token)
}

func GetCtxSess(req *srv.Req) (*Sess, error) {
	if req.Ctx["Sess"] == nil {
		err := errors.New("no session context, did you add the session middleware?")
		utils.Err(err)
		return nil, err
	}
	sess, ok := req.Ctx["Sess"].(*Sess)
	if !ok {
		err := errors.New("session from context is not of type *Sess")
		utils.Err(err)
		return nil, err
	}
	return sess, nil
}