package validator

import (
	"regexp"
	"strings"

	"golang.org/x/net/publicsuffix"
)

// based on W3C email regex, ref: https://www.w3.org/TR/2016/REC-html51-20161101/sec-forms.html#email-state-typeemail
var domainRegex = regexp.MustCompile(`^(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]$`)
var privateSuffix = []string{".etke.host"}

// Domain checks if domain is valid
func (v *V) Domain(domain string) bool {
	if domain == "" {
		return !v.enforce.Domain
	}

	if !v.DomainString(domain) {
		return false
	}

	return true
}

// DomainString checks if domain string / value is valid using string checks like length and regexp
func (v *V) DomainString(domain string) bool {
	if len(domain) < 4 || len(domain) > 77 {
		v.log.Info("domain %s invalid, reason: length", domain)
		return false
	}

	if !domainRegex.MatchString(domain) {
		v.log.Info("domain %s invalid, reason: regexp", domain)
		return false
	}

	return true
}

// GetBase returns base domain/host of the provided domain
func (v *V) GetBase(domain string) string {
	// domain without subdomain "example.com" has parts: example com
	minSize := 2
	if v.hasSuffix(domain) {
		// domain with a certain TLDs contains 3 parts: example.co.uk -> example co uk
		minSize = 3
	}

	parts := strings.Split(domain, ".")
	size := len(parts)
	// If domain contains only 2 parts (or less) - consider it without subdomains
	if size <= minSize {
		return domain
	}

	// return domain without subdomain (sub.example.com -> example.com; sub.example.co.uk -> example.co.uk)
	return strings.Join(parts[size-minSize:], ".")
}

// hasSuffix checks if domain has a suffix from public suffix list or from predefined suffix list
func (v *V) hasSuffix(domain string) bool {
	for _, suffix := range privateSuffix {
		if strings.HasSuffix(domain, suffix) {
			return true
		}
	}

	eTLD, _ := publicsuffix.PublicSuffix(domain)
	return strings.IndexByte(eTLD, '.') >= 0
}
