package entity

import (
	"encoding/binary"
	"errors"
	"fmt"
	"net/netip"
	"strings"

	"golang.org/x/text/cases"

	globalngv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/nextgen/v1"
)

const ipv4AddressSize = 4

type ResourcePool struct {
	*globalngv1.ResourcePool

	RegionId        uint64
	CloudProviderId uint64
	NormalizedName  string
	CanonicalCIDR   *IPv4Range
}

type IPv4Range struct {
	Start [ipv4AddressSize]byte
	End   [ipv4AddressSize]byte
}

// NormalizeResourcePoolName returns the tenant-wide equality key for a
// resource-pool display name.
func NormalizeResourcePoolName(name string) string {
	return cases.Fold().String(strings.TrimSpace(name))
}

// CanonicalIPv4Range converts an IPv4 CIDR into its inclusive, big-endian
// address bounds. The byte order preserves numeric IPv4 ordering when the
// values are stored in BINARY(4) columns.
func CanonicalIPv4Range(cidr string) (start, end []byte, err error) {
	prefix, err := netip.ParsePrefix(strings.TrimSpace(cidr))
	if err != nil {
		return nil, nil, fmt.Errorf("parse ipv4 cidr: %w", err)
	}
	if !prefix.Addr().Is4() {
		return nil, nil, errors.New("address prefix is not ipv4")
	}

	prefix = prefix.Masked()
	startAddress := prefix.Addr().As4()
	startValue := binary.BigEndian.Uint32(startAddress[:])
	hostMask := ^uint32(0) >> prefix.Bits()
	endValue := startValue | hostMask

	start = make([]byte, ipv4AddressSize)
	end = make([]byte, ipv4AddressSize)
	binary.BigEndian.PutUint32(start, startValue)
	binary.BigEndian.PutUint32(end, endValue)
	return start, end, nil
}

type ResourcePoolStrategy struct {
	*globalngv1.ResourcePoolStrategy

	RegionId        uint64
	CloudProviderId uint64
}

type ResourcePoolProfile = globalngv1.ResourcePoolProfile

type OrgRegionResourcePools struct {
	RegionId        uint64
	CloudProviderId uint64
	ResourcePools   []*ResourcePoolProfile
	Strategy        *ResourcePoolStrategy
}
