package services

import (
	"slices"
	"time"

	"github.com/go-playground/validator/v10"

	"GoMembership/internal/models"
	"GoMembership/internal/repositories"
	"GoMembership/internal/utils"
	"GoMembership/pkg/errors"
)

type MembershipServiceInterface interface {
	RegisterMembership(membership *models.Membership) (uint, error)
	FindMembershipByUserID(userID uint) (*models.Membership, error)
	RegisterSubscription(subscription *models.SubscriptionModel) (uint, error)
	GetMembershipModelNames() ([]string, error)
	GetModelByName(modelname *string) (*models.SubscriptionModel, error)
	GetSubscriptions(where map[string]interface{}) (*[]models.SubscriptionModel, error)
}

type MembershipService struct {
	Repo             repositories.MembershipRepositoryInterface
	SubscriptionRepo repositories.SubscriptionModelsRepositoryInterface
}

func (service *MembershipService) RegisterMembership(membership *models.Membership) (uint, error) {
	membership.StartDate = time.Now()
	return service.Repo.CreateMembership(membership)
}

func (service *MembershipService) FindMembershipByUserID(userID uint) (*models.Membership, error) {
	return service.Repo.FindMembershipByUserID(userID)
}

// Membership_Subscriptions
func (service *MembershipService) RegisterSubscription(subscription *models.SubscriptionModel) (uint, error) {
	if err := validateSubscriptionData(subscription); err != nil {
		return 0, err
	}
	return service.SubscriptionRepo.CreateSubscriptionModel(subscription)
}

func (service *MembershipService) GetMembershipModelNames() ([]string, error) {
	return service.SubscriptionRepo.GetMembershipModelNames()
}

func (service *MembershipService) GetModelByName(modelname *string) (*models.SubscriptionModel, error) {
	sModelNames, err := service.SubscriptionRepo.GetMembershipModelNames()
	if err != nil {
		return nil, err
	}

	if !slices.Contains(sModelNames, *modelname) {
		return nil, errors.ErrNotFound
	}
	return service.SubscriptionRepo.GetModelByName(modelname)
}

func (service *MembershipService) GetSubscriptions(where map[string]interface{}) (*[]models.SubscriptionModel, error) {
	return service.SubscriptionRepo.GetSubscriptions(where)
}

func validateSubscriptionData(subscription *models.SubscriptionModel) error {
	validate := validator.New()
	// subscriptionModel and membershipField don't have to be evaluated if adding a new subscription
	validate.RegisterValidation("subscriptionModel", func(fl validator.FieldLevel) bool { return true })
	validate.RegisterValidation("membershipField", func(fl validator.FieldLevel) bool { return true })
	validate.RegisterValidation("safe_content", utils.ValidateSafeContent)
	return validate.Struct(subscription)
}
