package link

import (
	"fmt"
	"net"
	"strings"
)

// ParseIPv4Netmask parses an IPv4 netmask string and returns the IPNet
func ParseIPv4Netmask(address, netmask string) (*net.IPNet, error) {
	if strings.Contains(address, "/") {
		_, ipNet, err := net.ParseCIDR(address)
		if err != nil {
			return nil, fmt.Errorf("invalid IPv4 address: %s", address)
		}
		return ipNet, nil
	}

	ip := net.ParseIP(address)
	if ip == nil {
		return nil, fmt.Errorf("invalid IPv4 address: %s", address)
	}
	if ip.To4() == nil {
		return nil, fmt.Errorf("not an IPv4 address: %s", address)
	}

	mask := net.ParseIP(netmask)
	if mask == nil {
		return nil, fmt.Errorf("invalid IPv4 netmask: %s", netmask)
	}
	if mask.To4() == nil {
		return nil, fmt.Errorf("not an IPv4 netmask: %s", netmask)
	}

	return &net.IPNet{
		IP:   ip,
		Mask: net.IPv4Mask(mask[12], mask[13], mask[14], mask[15]),
	}, nil
}

// ParseIPv6Prefix parses an IPv6 address and prefix length
func ParseIPv6Prefix(address string, prefixLength int) (*net.IPNet, error) {
	if strings.Contains(address, "/") {
		_, ipNet, err := net.ParseCIDR(address)
		if err != nil {
			return nil, fmt.Errorf("invalid IPv6 address: %s", address)
		}
		return ipNet, nil
	}

	ip := net.ParseIP(address)
	if ip == nil {
		return nil, fmt.Errorf("invalid IPv6 address: %s", address)
	}
	if ip.To16() == nil || ip.To4() != nil {
		return nil, fmt.Errorf("not an IPv6 address: %s", address)
	}

	if prefixLength < 0 || prefixLength > 128 {
		return nil, fmt.Errorf("invalid IPv6 prefix length: %d (must be 0-128)", prefixLength)
	}

	return &net.IPNet{
		IP:   ip,
		Mask: net.CIDRMask(prefixLength, 128),
	}, nil
}

// ValidateIPAddress validates an IP address
func ValidateIPAddress(address string, isIPv6 bool) error {
	ip := net.ParseIP(address)
	if ip == nil {
		return fmt.Errorf("invalid IP address: %s", address)
	}

	if isIPv6 {
		if ip.To16() == nil || ip.To4() != nil {
			return fmt.Errorf("not an IPv6 address: %s", address)
		}
	} else {
		if ip.To4() == nil {
			return fmt.Errorf("not an IPv4 address: %s", address)
		}
	}

	return nil
}
