package networkutils

import (
	"fmt"
	"math/rand"
	"net"
	"time"
)

type IPGenerator struct {
	netClient NetClient
	rand      *rand.Rand
}

func NewIPGenerator(netClient NetClient) IPGenerator {
	return IPGenerator{
		netClient: netClient,
		rand:      rand.New(rand.NewSource(time.Now().UnixNano())),
	}
}

func (ipgen IPGenerator) GenerateUniqueIP(cidrBlock string) (string, error) {
	_, cidr, err := net.ParseCIDR(cidrBlock)
	if err != nil {
		return "", err
	}
	uniqueIp, err := ipgen.randIp(cidr)
	if err != nil {
		return "", err
	}
	for IsIPInUse(ipgen.netClient, uniqueIp.String()) {
		uniqueIp, err = ipgen.randIp(cidr)
		if err != nil {
			return "", err
		}
	}
	return uniqueIp.String(), nil
}

// generates a random ip within the specified cidr block.
func (ipgen IPGenerator) randIp(cidr *net.IPNet) (net.IP, error) {
	newIp := *new(net.IP)
	for i := 0; i < 4; i++ {
		newIp = append(newIp, byte(ipgen.rand.Intn(255))&^cidr.Mask[i]|cidr.IP[i])
	}
	if !cidr.Contains(newIp) {
		return nil, fmt.Errorf("random IP generation failed")
	}
	return newIp, nil
}
