package transform

import (
	"fmt"
	"net/netip"
	"strings"

	"github.com/StackExchange/dnscontrol/v4/pkg/rfc4183"
)

// ReverseDomainName turns a CIDR block into a reversed (in-addr) name.
// For cases not covered by RFC2317, implement RFC4183
// The host bits must all be zeros.
func ReverseDomainName(cidr string) (string, error) {
	if rfc4183.IsRFC4183Mode() {
		return rfc4183.ReverseDomainName(cidr)
	}

	// Mask missing? Add it.
	if !strings.Contains(cidr, "/") {
		a, err := netip.ParseAddr(cidr)
		if err != nil {
			return "", fmt.Errorf("not an IP address: %w", err)
		}
		if a.Is4() {
			cidr = cidr + "/32"
		} else {
			cidr = cidr + "/128"
		}
	}

	// Parse the CIDR.
	p, err := netip.ParsePrefix(cidr)
	if err != nil {
		return "", fmt.Errorf("not a CIDR block: %w", err)
	}
	bits := p.Bits()

	if p.Masked() != p {
		return "", fmt.Errorf("CIDR %v has 1 bits beyond the mask", cidr)
	}

	// Cases where RFC4183 is the same as RFC2317:
	// IPV6, /0 - /24, /32
	if strings.Contains(cidr, ":") || bits <= 24 || bits == 32 {
		// There is no p.Is6() so we test for ":" as a workaround.
		return rfc4183.ReverseDomainName(cidr)
	}

	// Record that the change to --revmode default will affect this configuration
	rfc4183.NeedsWarning()

	// Handle IPv4 "Classless in-addr.arpa delegation" RFC2317:
	// if bits >= 25 && bits < 32 {
	// first address / netmask . Class-b-arpa.

	ip := p.Addr().AsSlice()
	return fmt.Sprintf("%d/%d.%d.%d.%d.in-addr.arpa",
		ip[3], bits, ip[2], ip[1], ip[0]), nil
}
