package validators

import (
	"fmt"
	"strings"

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

func errorMessage(fe validator.FieldError) string {
	prefix := "validation-error:"

	switch fe.Tag() {

	// Common Validators
	case "required":
		return fmt.Sprintf("%s %s is required", prefix, fe.Field())
	case "required_without_all":
		return fmt.Sprintf("%s at least one of the following must be specified: %s",
			prefix,
			joinValues(append([]string{fe.Field()}, strings.Fields(fe.Param())...)))
	case "gt":
		return fmt.Sprintf("%s %s can't be less or equal to zero", prefix, fe.Field())
	case "min":
		return fmt.Sprintf("%s %s: not enough elements", prefix, fe.Field())
	case "max":
		return fmt.Sprintf("%s %s: too many elements", prefix, fe.Field())
	case "url":
		return fmt.Sprintf("%s %s: unexpected URL format", prefix, fe.Field())
	case "email":
		return fmt.Sprintf("%s %s: unexpected E-Mail format", prefix, fe.Field())
	case "mac":
		return fmt.Sprintf("%s %s: unexpected MAC address format", prefix, fe.Field())
	case "isBool":
		return fmt.Sprintf("%s %s: must be bool type", prefix, fe.Field())
	case "isString":
		return fmt.Sprintf("%s %s: must be string type", prefix, fe.Field())

	case "accessType":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(accessTypeValues))

	case "resTypes":
		return fmt.Sprintf("%s %s can contain only the following values: %s",
			prefix,
			fe.Field(),
			joinValues(resTypesValues))

	case "proto":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(protoValues))

	// apiGroup Validators
	case "apiGroup":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(apiGroupValues))

	// Account Validators
	case "accountCUType":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(accountCUTypeValues))

	// BService Validators
	case "bserviceMode":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(bserviceModeValues))

	// Compute Validators
	case "computeTopology":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(computeTopologyValues))

	case "computePolicy":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(computePolicyValues))

	case "computeMode":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(computeModeValues))

	case "mtu":
		return fmt.Sprint(prefix, fe.Field(), "must be ", mtuMin, "-", mtuMax)

	case "preferredCPU":
		return fmt.Sprint(prefix, fe.Field(), "must be equal to or greater than", -1)

	case "computex86NetType":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(computex86NetTypeValues))

	case "computeNetType":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(computeNetTypeValues))

	case "computeOrder":
		return fmt.Sprintf("%s %s can contain only the following values: %s",
			prefix,
			fe.Field(),
			joinValues(computeOrderValues))

	case "computeDataDisks":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(computeDataDisksValues))

	// Flipgroup Validators
	case "flipgroupClientType":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(flipgroupClientTypeValues))

		// k8s Validators
	case "workerGroupName":
		return fmt.Sprintf("%s %s must be more 3 symbol",
			prefix,
			fe.Field())

	// KVM_X86 Mass create validators
	case "massCreateNetType":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(massCreateNetTypeValues))

	// LB Validators
	case "lbAlgorithm":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(lbAlgorithmValues))

	// RG Validators
	case "rgDefNet":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(rgDefNetValues))

	case "rgNetType":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(rgNetTypeValues))

	// ViNS Validators
	case "vinsType":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(vinsTypeValues))

	// Image Validators
	case "imageBootType":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(imageBootTypeValues))

	case "imageType":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(imageTypeValues))

	case "imageArchitecture":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(imageArchitectureValues))

	// SEP Validators
	case "sepFieldType":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(sepFieldTypeValues))

	// HWPath Validators
	case "hwPath":
		return fmt.Sprintf("%s %s must be in format 0000:1f:2b.0",
			prefix,
			fe.Field())

	// Network plugin Validators
	case "networkPlugin":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(networkPluginValues))

	case "networkPlugins":
		return fmt.Sprintf("%s %s must contain only the following: %s",
			prefix,
			fe.Field(),
			joinValues(networkPluginValues))

	case "strict_loose":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(strictLooseValues))

	case "interfaceState":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(interfaceStateValues))

	case "interfaceTXModel":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(txModelValues))

	case "interfaceIOEventFD":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(ioEventFDValues))

	case "interfaceEventIDx":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(eventIDxValues))

	case "sortBy":
		return fmt.Sprintf("%s %s must be in format +|-(field)",
			prefix,
			fe.Field())

	case "action":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(actionValues))

	case "vmaction":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(vmActionValues))

	case "computeFeatures":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(computeFeaturesValues))

	case "networkInterfaceNaming":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(networkInterfaceNamingValues))

	case "numaAffinity":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(numaAffinityValues))

	case "kvmx86NetType":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(kvmx86NetTypeValues))

	case "chipset":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(chipsetValues))

	case "loaderType":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(loaderTypeValues))

	case "language":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(languageValues))

	case "sepType":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(sepTypeValues))

	// user validators
	case "userProvider":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(userProviders))

	// security group validators
	case "securityGroupDirection":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(securityGroupDirectionValues))

	case "securityGroupEthertype":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(securityGroupEthertypeValues))

	case "securityGroupProtocol":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(securityGroupProtocolValues))

	// trunk tags validator
	case "trunkTags":
		return fmt.Sprintf("%s %s must be in range from 1 to 4095",
			prefix,
			fe.Field())

		// addressPoolNetTypeValidator validator
	case "addressPoolNetTypeValidator":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(addressPoolNetTypeValues))

	case "device":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(deviceValues))

	case "ipTypes":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(ipTypeValues))

	case "sepTechStatus":
		return fmt.Sprintf("%s %s must be one of the following: %s",
			prefix,
			fe.Field(),
			joinValues(sepTechStatusValues))
	}

	return fe.Error()
}

func joinValues(values []string) string {
	return strings.Join(values, ", ")
}
