package services

import (
	"strings"

	"GoMembership/internal/constants"
	"GoMembership/internal/models"
	"GoMembership/internal/repositories"
	"GoMembership/pkg/errors"

	"gorm.io/gorm"

	"time"
)

type UserServiceInterface interface {
	RegisterUser(user *models.User) (id uint, token string, err error)
	GetUserByEmail(email string) (*models.User, error)
	GetUserByID(id uint) (*models.User, error)
	GetUsers(where map[string]interface{}) (*[]models.User, error)
	UpdateUser(user *models.User) (*models.User, error)
	DeleteUser(lastname string, id uint) error
	SetUserStatus(id uint, status uint) error
	VerifyUser(token *string, verificationType *string) (*models.Verification, error)
	SetVerificationToken(id *uint, verificationType *string) (string, error)
	RevokeVerification(id *uint, verificationType string) error
	HandlePasswordChangeRequest(user *models.User) (token string, err error)
}

type UserService struct {
	Repo     repositories.UserRepositoryInterface
	Licences repositories.LicenceInterface
}

func (service *UserService) DeleteUser(lastname string, id uint) error {
	if id == 0 || lastname == "" {
		return errors.ErrNoData
	}

	user, err := service.GetUserByID(id)
	if err != nil {
		return err
	}
	if user == nil {
		return errors.ErrUserNotFound
	}

	return service.Repo.DeleteUser(id)
}

func (service *UserService) UpdateUser(user *models.User) (*models.User, error) {

	if user.ID == 0 {
		return nil, errors.ErrUserNotFound
	}

	user.SetPassword(user.Password)

	// Validate subscription model
	selectedModel, err := repositories.GetSubscriptionByName(&user.Membership.SubscriptionModel.Name)
	if err != nil {
		return nil, errors.ErrSubscriptionNotFound
	}
	user.Membership.SubscriptionModel = *selectedModel
	user.Membership.SubscriptionModelID = selectedModel.ID

	updatedUser, err := service.Repo.UpdateUser(user)

	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, errors.ErrUserNotFound
		}
		if strings.Contains(err.Error(), "UNIQUE constraint failed") {
			return nil, errors.ErrDuplicateEntry
		}
		return nil, err
	}

	return updatedUser, nil
}

func (service *UserService) RegisterUser(user *models.User) (id uint, token string, err error) {

	user.SetPassword(user.Password)

	user.Status = constants.UnverifiedStatus
	user.CreatedAt = time.Now()
	user.UpdatedAt = time.Now()
	user.PaymentStatus = constants.AwaitingPaymentStatus
	user.BankAccount.MandateDateSigned = time.Now()
	id, err = service.Repo.CreateUser(user)
	if err != nil {
		return 0, "", err
	}

	token, err = service.SetVerificationToken(&id, &constants.VerificationTypes.Email)
	if err != nil {
		return 0, "", err
	}
	return id, token, nil
}

func (service *UserService) GetUserByID(id uint) (*models.User, error) {
	return repositories.GetUserByID(&id)
}

func (service *UserService) GetUserByEmail(email string) (*models.User, error) {
	return service.Repo.GetUserByEmail(email)
}

func (service *UserService) GetUsers(where map[string]interface{}) (*[]models.User, error) {
	if where == nil {
		where = map[string]interface{}{}
	}
	return service.Repo.GetUsers(where)
}
