package netsplit

import (
	`fmt`
	`net/netip`

	`go4.org/netipx`
)

// Split is to conform to a NetSplitter, though a PrefixGetter is *technically* not a splitter.
func (p *PrefixGetter) Split() (nets []*netip.Prefix, remaining *netipx.IPSet, err error) {

	var ok bool
	var base netip.Prefix
	var vlsmS *VLSMSplitter
	var addr netip.Addr
	var maxPfxLen uint8 = maxBitsv4
	var ipsb *netipx.IPSetBuilder = new(netipx.IPSetBuilder)

	if p == nil || p.PrefixLength == 0 || p.BaseSplitter == nil || p.network == nil {
		return
	}

	if err = validate.Struct(p); err != nil {
		return
	}

	// If the position is "first", we can simply call a VLSM.
	if p.Pos == "first" {
		vlsmS = &VLSMSplitter{
			Ascending:     false,
			Explicit:      false,
			PrefixLengths: []uint8{p.PrefixLength},
			BaseSplitter:  p.BaseSplitter,
		}
		if nets, remaining, err = vlsmS.Split(); err != nil {
			return
		}
		return
	}

	if p.Pos != "last" {
		err = ErrUnknownPos
		return
	}

	// Otherwise this gets... messy.
	if base, ok = netipx.FromStdIPNet(p.network); !ok {
		err = ErrBadBoundary
		return
	}
	if !base.IsValid() {
		err = ErrBadBoundary
		return
	}
	ipsb = new(netipx.IPSetBuilder)
	ipsb.AddPrefix(base.Masked())

	// First if it's a single host prefix, ezpz gg no re.
	if base.Addr().Is6() {
		maxPfxLen = maxBitsv6
	}
	if p.PrefixLength == maxPfxLen {
		nets = make([]*netip.Prefix, 1)
		nets[0] = new(netip.Prefix)
		addr = netipx.PrefixLastIP(base)
		fmt.Println(addr.String())
		if *nets[0], err = addr.Prefix(int(p.PrefixLength)); err != nil {
			return
		}
		ipsb.Remove(addr)
		if remaining, err = ipsb.IPSet(); err != nil {
			return
		}
		return
	}

	// Otherwise this gets... interesting.
	/*
		For IPv4, performance NORMALLY would be "fine" on modern hardware with:
			1. straight CIDR-splitting
			2. grabbing the last prefix
			3. condensing the leading prefixes to a new IPSet
		But even this can take a long time (see CIDRSplitter.Split comments).

		In almost all cases (unless subnetting like, n+12 prefix length),
		IPv6 takes WAY too long.

		So use the same function (LastSubnetPfx) for both cases.
	*/
	nets = make([]*netip.Prefix, 1)
	nets[0] = new(netip.Prefix)
	if *nets[0], err = LastSubnetPfx(base, p.PrefixLength); err != nil {
		return
	}
	ipsb.RemovePrefix(*nets[0])
	if remaining, err = ipsb.IPSet(); err != nil {
		return
	}

	return
}