package auth

import (
	_ "embed"
	"strings"
)

//go:embed disposable_domains.txt
var disposableList string

// disposableDomains is the parsed blocklist, built once at package init.
var disposableDomains = parseDisposable(disposableList)

// parseDisposable turns the embedded wordlist into a lookup set.
func parseDisposable(raw string) map[string]struct{} {
	set := make(map[string]struct{})
	for _, line := range strings.Split(raw, "\n") {
		line = strings.TrimSpace(strings.ToLower(line))
		if line == "" || strings.HasPrefix(line, "#") {
			continue
		}
		set[line] = struct{}{}
	}
	return set
}

// NormalizeEmail lowercases and trims the address for consistent storage and
// rate-limit keying. It does not alter the local part beyond trimming.
func NormalizeEmail(email string) string {
	return strings.ToLower(strings.TrimSpace(email))
}

// emailDomain returns the lowercased domain part of an email, or "" if the
// address has no single '@'.
func emailDomain(email string) string {
	at := strings.LastIndex(email, "@")
	if at < 0 || at == len(email)-1 {
		return ""
	}
	return strings.ToLower(email[at+1:])
}

// ValidEmail performs a cheap structural sanity check: exactly one '@', a
// non-empty local part, and a domain containing a dot. It is deliberately
// permissive — true deliverability is proven by the verification code.
func ValidEmail(email string) bool {
	email = strings.TrimSpace(email)
	if len(email) < 3 || len(email) > 254 {
		return false
	}
	at := strings.IndexByte(email, '@')
	if at <= 0 || at != strings.LastIndexByte(email, '@') {
		return false
	}
	domain := email[at+1:]
	return strings.Contains(domain, ".") && !strings.HasPrefix(domain, ".") && !strings.HasSuffix(domain, ".")
}

// IsDisposable reports whether the email's domain is on the disposable-domain
// blocklist.
func IsDisposable(email string) bool {
	domain := emailDomain(email)
	if domain == "" {
		return false
	}
	_, ok := disposableDomains[domain]
	return ok
}
