package user

import (
	"time"

	"git.umbach.dev/app-idea/rest-api/modules/database"
	"git.umbach.dev/app-idea/rest-api/modules/structs"
	"github.com/gofiber/fiber/v2"
	ua "github.com/mileusna/useragent"
	log "github.com/sirupsen/logrus"
	"gorm.io/gorm"
)

func isSessionIdValid(sessionId string) bool {
	deleteExpiredSessions(database.DB)

	var res string
	db := database.DB

	db.Raw("SELECT "+cfg.Settings.Cookies.SessionId+" FROM sessions WHERE "+cfg.Settings.Cookies.SessionId+" = ?", sessionId).Scan(&res)

	if res == "" {
		return false
	} else {
		return true
	}
}

func DeleteSession(c *fiber.Ctx) error {
	// swagger:operation POST /sessions/{id} Sessions sessions
	// ---
	// summary: Delete a user sessions
	// responses:
	//   '200':
	//     description: User informations
	//   '400':
	//     description: Session id invalid

	db := database.DB

	userId, err := getUserIdBySessionId(c.Cookies(cfg.Settings.Cookies.SessionId))

	if err != nil {
		return c.SendStatus(fiber.StatusInternalServerError)
	}

	res := db.Where("user_id = ? AND session_id = ?", userId, c.Cookies(cfg.Settings.Cookies.SessionId)).Delete(&structs.Session{})

	// session isn't in list
	if res.RowsAffected == 0 {
		return c.SendStatus(fiber.StatusBadRequest)
	}

	return c.SendStatus(fiber.StatusOK)
}

func deleteExpiredSessions(db *gorm.DB) {
	var res string

	db.Raw("DELETE FROM sessions WHERE expires < ?", time.Now()).Scan(&res)
}

func createUserSession(db *gorm.DB, userId string, ip string, userAgent string) (string, error) {
	sessionId, err := generateRandomString(32, 1)

	if err != nil {
		log.Warnln("Failed to generate user session:", err)
		return "", err
	}

	ua := ua.Parse(userAgent)
	session := structs.Session{UserId: userId, SessionId: sessionId, IP: ip, UserAgent: ua.OS + " " + ua.Name, LastLogin: time.Now(), Expires: getUserSessionExpiresTime()}

	res := db.Create(&session)

	if res.Error != nil {
		log.Warnln("failed to create session:", res.Error)
		return "", err
	}

	return sessionId, nil
}

func getUserSessionExpiresTime() time.Time {
	return time.Now().Add(time.Hour * time.Duration(cfg.Settings.Expires.UserSession))
}

func SessionIdCheck(c *fiber.Ctx) error {
	sessionId := c.Cookies(cfg.Settings.Cookies.SessionId)

	log.Debugln("SessionIdCheck", sessionId)

	if sessionId == "" {
		return fiber.ErrUnauthorized
	}

	valid := isSessionIdValid(sessionId)

	if valid {
		return c.Next()
	}

	return fiber.ErrUnauthorized
}

func AuthSession(c *fiber.Ctx) error {
	sessionId := c.Cookies(cfg.Settings.Cookies.SessionId)

	log.Infoln("cookie", sessionId, c.IP())

	auth := c.Get(fiber.HeaderAuthorization)

	log.Infoln("auth", auth, c.Get("credentials"))

	if sessionId == "" {
		return fiber.ErrUnauthorized
	}

	valid := isSessionIdValid(sessionId)

	if valid {
		return c.SendStatus(fiber.StatusOK)
	}

	return c.SendStatus(fiber.StatusUnauthorized)
}
