package session

import (
	"ddpf/model/dbm"
	"github.com/tangs-drm/go-tool/util"
	"github.com/tangs-drm/go-tool/log"
	thttp "github.com/tangs-drm/go-tool/http"
	"net/http"
)

var Max_Session_Num = 10
var Valid_Session_Time int64 = 2592000 // 一个月

var SessionLog bool

func slog(format string, args... interface{}) {
	if SessionLog {
		log.LogD_(3, format, args...)
	}
}

// UserFilterFunc过滤器,检查用户是否是登录状态
var UserFilterFunc thttp.FilterFunc = func(w http.ResponseWriter, r *http.Request) int {
	cookie, err := r.Cookie("token")
	slog("%v", util.S2Json(cookie))
	if err != nil {
		slog("[UserFilterFunc] get cookie token error ->(%v)", err)
		http.Redirect(w, r, "/", 301)
		return thttp.REQUEST_RETURN
	}
	token := cookie.Value
	// token 是36位的UUID,形如4C2FB50E-C530-7868-01DF-165B2BC47308
	if len(token) != 36 {
		slog("[UserFilterFunc] get invalid token(%v)", token)
		http.Redirect(w, r, "/", 301)
		return thttp.REQUEST_RETURN
	}

	// 检查token是否合法
	valid, err := CheckValidSession(token)
	if err != nil {
		slog("[UserFilterFunc] check token(%v) error -> (%v)", token, err)
		http.Redirect(w, r, "/", 301)
		return thttp.REQUEST_RETURN
	}

	if !valid {
		slog("[UserFilterFunc] check token(%v) is invalid", token)
		http.Redirect(w, r, "/", 301)
		return thttp.REQUEST_RETURN
	}

	err = FlushSession(token)
	if err != nil {
		slog("[UserFilterFunc] flush token with token(%v) error ->(%v)", token, err)
	}

	slog("--------------")
	return thttp.REQUEST_CONTINUE
}

/*
arg
	uid: 用户id
desc
	CreateSession 创建用户对应的session值
ret
	0:包含了用户信息的session对象
	1:创建session的错误信息，非nil表示有错误
*/
func CreateSession(uid string) (*Session, error) {
	session := &Session{
		Id:util.UUID(),
		Uid:uid,
		Time:util.Now10(),
		LastTime:util.Now10(),
	}
	var sqlString string = "INSERT INTO SESSION(ID,UID,TIME,LASTTIME) VALUE(?,?,?,?);"
	stmt, err := dbm.Db().Prepare(sqlString)
	if err != nil {
		log.Error("CreateSession Prepare by session(%v) error ->(%v)", util.S2Json(session), err)
		return nil, err
	}
	defer stmt.Close()
	_, err = stmt.Exec(session.Id, session.Uid, session.Time, session.LastTime)
	if err != nil {
		log.Error("CreateSession Exec by session(%v) error ->(%v)", util.S2Json(session), err)
		return nil, err
	}

	log.Debug("CreateSession by id(%v), uid(%v), lastTime(%v) success", session.Id, session.Uid, session.LastTime)
	return session, nil
}

// CheckValidSession 是检查用户的session是否有效
// 检查的指标有session是否存在,有效的session个数,session的有效时间
// 返回值1 false: 无效, true: 有效
// 返回值2 是否有错误信息,如有错误,返回err,否则返回nil
func CheckValidSession(session string) (bool, error) {
	if len(session) < 1 {
		return false, nil
	}
	var sqlString = "SELECT collect.ID, collect.LASTTIME FROM (SELECT ID, LASTTIME FROM SESSION ORDER BY LASTTIME DESC LIMIT ?) as collect WHERE ID = ?;"
	rows, err := dbm.Db().Query(sqlString, Max_Session_Num, session)
	if err != nil {
		log.Error("CheckValidSession Query by session(%v), Max_Session_Num(%v) error ->(%v)", session, Max_Session_Num, err)
		return false, err
	}
	defer rows.Close()

	if !rows.Next() {
		return false, nil
	}

	var id string
	var lastTime int64
	err = rows.Scan(&id, &lastTime)
	if err != nil {
		log.Error("CheckValidSession Scan result by session(%v) error ->(%v)", session)
		return false, err
	}

	validTime := lastTime + Valid_Session_Time

	log.Debug("%v, %v, %v, %v, %v", validTime, util.Now10(), lastTime, Valid_Session_Time, validTime > util.Now10())
	if validTime > util.Now10() {
		return true, nil
	}
	return false, nil
}

// FlushToken更新session对应的最后一个登录时间
// session 用户对用的sessionID
// 返回值：非nil表示有错误
func FlushSession(session string) error {
	var sqlString = "UPDATE SESSION SET LASTTIME = ? WHERE ID = ?;"
	stmt, err := dbm.Db().Prepare(sqlString)
	if err != nil {
		return err
	}
	defer stmt.Close()

	_, err = stmt.Exec(util.Now10(), session)
	return err
}