package utils

// import "regexp"

import (
	"GoMembership/internal/database"
	"GoMembership/internal/models"
	"GoMembership/pkg/logger"
	"reflect"
	"regexp"
	"slices"
	"strings"
	"time"

	"github.com/go-playground/validator/v10"
	"github.com/jbub/banking/iban"
	"github.com/jbub/banking/swift"
)

var xssPatterns = []*regexp.Regexp{
	regexp.MustCompile(`(?i)<script`),
	regexp.MustCompile(`(?i)javascript:`),
	regexp.MustCompile(`(?i)on\w+\s*=`),
	regexp.MustCompile(`(?i)(vbscript|data):`),
	regexp.MustCompile(`(?i)<(iframe|object|embed|applet)`),
	regexp.MustCompile(`(?i)expression\s*\(`),
	regexp.MustCompile(`(?i)url\s*\(`),
	regexp.MustCompile(`(?i)<\?`),
	regexp.MustCompile(`(?i)<%`),
	regexp.MustCompile(`(?i)<!\[CDATA\[`),
	regexp.MustCompile(`(?i)<(svg|animate)`),
	regexp.MustCompile(`(?i)<(audio|video|source)`),
	regexp.MustCompile(`(?i)base64`),
}

func AgeValidator(fl validator.FieldLevel) bool {
	fieldValue := fl.Field()
	dateOfBirth := fieldValue.Interface().(time.Time)
	now := time.Now()
	age := now.Year() - dateOfBirth.Year()

	if now.YearDay() < dateOfBirth.YearDay() {
		age-- // if birthday is in the future..
	}

	return age >= 18
}

func SubscriptionModelValidator(fl validator.FieldLevel) bool {
	fieldValue := fl.Field().String()
	var names []string
	if err := database.DB.Model(&models.SubscriptionModel{}).Pluck("name", &names).Error; err != nil {
		logger.Error.Fatalf("Couldn't get SubscriptionModel names: %#v", err)
		return false
	}
	return slices.Contains(names, fieldValue)
}

func IBANValidator(fl validator.FieldLevel) bool {
	fieldValue := fl.Field().String()

	return iban.Validate(fieldValue) == nil
}

func ValidateRequiredMembershipField(fl validator.FieldLevel) bool {
	user := fl.Top().Interface().(*models.User)
	membership := user.Membership
	subModel := membership.SubscriptionModel

	// Get the field name specified in RequiredMembershipField
	fieldName := subModel.RequiredMembershipField
	if fieldName == "" {
		return true
	}

	// Get the value of the field specified by RequiredMembershipField
	fieldValue := reflect.ValueOf(membership).FieldByName(fieldName)

	logger.Info.Printf("Starting fieldValue Validation for %v: %#v", fieldName, fieldValue)

	// Check if the fieldValue is valid
	if !fieldValue.IsValid() {
		return false
	}

	logger.Info.Printf("fieldValue is valid: %#v", fieldValue)

	// Check if the fieldValue is a nil pointer
	if fieldValue.Kind() == reflect.Ptr && fieldValue.IsNil() {
		return false
	}

	logger.Info.Println("fieldValue is not a nil pointer")

	// Ensure that the fieldValue is an int64
	var fieldInt64 int64
	if fieldValue.Kind() == reflect.Int64 {
		fieldInt64 = fieldValue.Int()
	} else {
		return false
	}

	logger.Info.Println("fieldValue is a int")

	var membershipIDs []int64
	if err := database.DB.Model(&models.Membership{}).Pluck("id", &membershipIDs).Error; err != nil {
		logger.Error.Fatalf("Couldn't get SubscriptionModel names: %#v", err)
		return false
	}

	logger.Info.Printf("found ids of members: %#v", membershipIDs)

	// logger.Info.Printf("FIELD_NAME: %#v\nVALUE: %#v", fieldName, fieldValue)
	// Check if the field value is zero (empty)
	return slices.Contains(membershipIDs, fieldInt64)
}

func BICValidator(fl validator.FieldLevel) bool {
	fieldValue := fl.Field().String()

	return swift.Validate(fieldValue) == nil
}

func ValidateSafeContent(fl validator.FieldLevel) bool {
	input := strings.ToLower(fl.Field().String())
	for _, pattern := range xssPatterns {
		if pattern.MatchString(input) {
			return false
		}
	}
	return true
}
