const IPV6_GROUPS = 8;
const IPV6_PREFIX_GROUPS = 4;
/**
* An IPv6 client typically holds a whole /64, so keying on the full address lets it rotate past every
* per-IP limit. IPv6 collapses to its /64 prefix; IPv4 stays exact.
*/
export function ipBucket(ip: string): string {
if (!ip.includes(":") || ip.includes(".")) return ip;
const halves = ip.toLowerCase().split("::");
if (halves.length > 2) return ip;
const [head, tail = ""] = halves;
const left = head ? head.split(":") : [];
const right = tail ? tail.split(":") : [];
if ([...left, ...right].some((group) => !/^[0-9a-f]{1,4}$/.test(group))) return ip;
if (!ip.includes("::") && left.length !== IPV6_GROUPS) return ip;
const fill = Math.max(0, IPV6_GROUPS - left.length - right.length);
const groups = [...left, ...Array<string>(fill).fill("0"), ...right];
if (groups.length !== IPV6_GROUPS) return ip;
return `${groups
.slice(0, IPV6_PREFIX_GROUPS)
.map((group) => group.replace(/^0+(?=.)/, ""))
.join(":")}::/64`;
}