package network

import (
	"fmt"
	"net"
)

type SubnetOverlap struct {
	Interface string `json:"interface"`
	Subnet    string `json:"subnet"`
	Label     string `json:"label,omitempty"`
}

func parseIPNet(ipStr, maskStr string) (*net.IPNet, error) {
	ip := net.ParseIP(ipStr)
	if ip == nil {
		return nil, fmt.Errorf("invalid IP: %s", ipStr)
	}
	ip = ip.To4()
	if ip == nil {
		return nil, fmt.Errorf("invalid IPv4: %s", ipStr)
	}

	mask := ipMaskFromString(maskStr)
	if mask == nil {
		return nil, fmt.Errorf("invalid netmask: %s", maskStr)
	}

	return &net.IPNet{IP: ip.Mask(mask), Mask: mask}, nil
}

func ipMaskFromString(maskStr string) net.IPMask {
	m := net.ParseIP(maskStr)
	if m != nil {
		if m4 := m.To4(); m4 != nil {
			return net.IPMask(m4)
		}
	}
	return nil
}

func subnetsOverlap(a, b *net.IPNet) bool {
	return a.Contains(b.IP) || b.Contains(a.IP)
}

func CheckOverlap(newIP, newMask, excludeIface string, existing []SubnetOverlap) []SubnetOverlap {
	newNet, err := parseIPNet(newIP, newMask)
	if err != nil {
		return nil
	}

	var result []SubnetOverlap
	for _, s := range existing {
		if s.Interface == excludeIface {
			continue
		}
		parts, err := parseSubnetStr(s.Subnet)
		if err != nil {
			continue
		}
		existingNet, err := parseIPNet(parts[0], parts[1])
		if err != nil {
			continue
		}
		if subnetsOverlap(newNet, existingNet) {
			result = append(result, s)
		}
	}
	return result
}

func ParseSubnet(ipStr, maskStr string) (string, error) {
	n, err := parseIPNet(ipStr, maskStr)
	if err != nil {
		return "", err
	}
	return n.String(), nil
}

func parseSubnetStr(s string) ([2]string, error) {
	for i := len(s) - 1; i >= 0; i-- {
		if s[i] == '/' {
			return [2]string{s[:i], s[i+1:]}, nil
		}
	}
	return [2]string{}, fmt.Errorf("invalid subnet format: %s", s)
}