package dns

import (
	"net"
	"strings"
	"time"

	"github.com/hashicorp/golang-lru/v2"
)

type lookupCacheEntry struct {
	cachedName string
	timestamp  time.Time
}

var lookupCacheValidity = 30 * time.Second

var lookupCache *lru.Cache[string, lookupCacheEntry]

var defaultPagesRepo = "pages"

// GetTargetFromDNS searches for CNAME or TXT entries on the request domain ending with MainDomainSuffix.
// If everything is fine, it returns the target data.
func GetTargetFromDNS(domain, mainDomainSuffix, firstDefaultBranch string) (targetOwner, targetRepo, targetBranch string) {
	// Get CNAME or TXT
	var cname string
	var err error

	if lookupCache == nil {
		lookupCache, err = lru.New[string, lookupCacheEntry](4096)
		if err != nil {
			panic(err) // This should only happen if 4096 < 0 at the time of writing, which should be reason enough to panic.
		}
	}
	if entry, ok := lookupCache.Get(domain); ok && time.Now().Before(entry.timestamp.Add(lookupCacheValidity)) {
		cname = entry.cachedName
	} else {
		cname, err = net.LookupCNAME(domain)
		cname = strings.TrimSuffix(cname, ".")
		if err != nil || !strings.HasSuffix(cname, mainDomainSuffix) {
			cname = ""
			// TODO: check if the A record matches!
			names, err := net.LookupTXT(domain)
			if err == nil {
				for _, name := range names {
					name = strings.TrimSuffix(strings.TrimSpace(name), ".")
					if strings.HasSuffix(name, mainDomainSuffix) {
						cname = name
						break
					}
				}
			}
		}
		_ = lookupCache.Add(domain, lookupCacheEntry{
			cname,
			time.Now(),
		})
	}
	if cname == "" {
		return
	}
	cnameParts := strings.Split(strings.TrimSuffix(cname, mainDomainSuffix), ".")
	targetOwner = cnameParts[len(cnameParts)-1]
	if len(cnameParts) > 1 {
		targetRepo = cnameParts[len(cnameParts)-2]
	}
	if len(cnameParts) > 2 {
		targetBranch = cnameParts[len(cnameParts)-3]
	}
	if targetRepo == "" {
		targetRepo = defaultPagesRepo
	}
	if targetBranch == "" && targetRepo != defaultPagesRepo {
		targetBranch = firstDefaultBranch
	}
	// if targetBranch is still empty, the caller must find the default branch
	return
}