package user

import (
	"errors"
	"fmt"
	"strconv"
	"time"

	"github.com/golang-jwt/jwt"
	"github.com/jinzhu/gorm"
	"gitlab.com/pactual1/backend/config"
	"gitlab.com/pactual1/backend/models"
	"gitlab.com/pactual1/backend/shared"
	"golang.org/x/crypto/bcrypt"
)

func SaveResetTokenToDB(userID uint, resetToken string) error {
	// Calculate the expiry date (one month from now)
	expiryDate := time.Now().AddDate(0, 1, 0).Format(time.RFC3339)

	// Create a new PasswordTokens instance
	passwordToken := models.PasswordTokens{
		UserID:     userID,
		Token:      resetToken,
		ExpiryDate: expiryDate,
	}

	// Save the password token to the database
	if err := shared.GetDb().Create(&passwordToken).Error; err != nil {
		return err
	}

	return nil
}

func GetUserByEmail(email string) (*models.User, error) {
	var user models.User

	// Query the database for a user with the specified email
	if err := shared.GetDb().Where("email = ?", email).First(&user).Error; err != nil {
		if gorm.IsRecordNotFoundError(err) {
			return nil, nil
		}
		return nil, err
	}

	return &user, nil
}

func CheckPassword(hashedPassword, password string) bool {
	err := bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(password))
	return err == nil
}

func CreateSessionToken(userID, companyID uint) (string, error) {
	// Generate JWT token
	tokenString, err := CreateJWTToken(userID)
	if err != nil {
		return "", err
	}

	// Create and save the session token in the database
	sessionToken := models.SessionToken{
		UserID:    userID,
		Token:     tokenString,
		CompanyID: companyID,
		IsActive:  true,
	}
	if result := shared.GetDb().Create(&sessionToken); result.Error != nil {
		return "", result.Error
	}

	return tokenString, nil
}

func ResetLoginAttempts(user models.User) {
	user.LoginAttempts = 0
	user.IsActive = true
	shared.GetDb().Save(&user)
}

func IncrementLoginAttempts(user models.User) {
	user.LoginAttempts++
	if user.LoginAttempts >= 10 {
		user.IsActive = false
	}
	shared.GetDb().Save(&user)
}

func CreateJWTToken(userID uint) (string, error) {
	var jwtKey = []byte(config.AppConfig.Service.JwtSecretKey)
	expiryHours, err := strconv.Atoi(config.AppConfig.Service.JwtSecretKeyExpiryHours)

	if err != nil {
		return "", err
	}

	expirationTime := time.Now().Add(time.Duration(expiryHours) * time.Hour)
	claims := &jwt.StandardClaims{
		Subject:   fmt.Sprint(userID),
		ExpiresAt: expirationTime.Unix(),
	}

	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	tokenString, err := token.SignedString(jwtKey)
	if err != nil {
		return "", err
	}

	return tokenString, nil
}

func InvalidateSessionToken(tokenString string) error {
	// Find the session token in the database
	var sessionToken models.SessionToken
	result := shared.GetDb().Where("token = ?", tokenString).First(&sessionToken)
	if result.Error != nil {
		if errors.Is(result.Error, gorm.ErrRecordNotFound) {
			// If token is not found, you may choose to ignore or handle it as an error
			return nil // or return result.Error for strict handling
		}
		return result.Error
	}

	return shared.GetDb().Delete(&sessionToken).Error
}
