package pgtype

import (
	
	
	
	
	
)

// Network address family is dependent on server socket.h value for AF_INET.
// In practice, all platforms appear to have the same value. See
// src/include/utils/inet.h for more information.
const (
	defaultAFInet  = 2
	defaultAFInet6 = 3
)

type NetipPrefixScanner interface {
	ScanNetipPrefix(v netip.Prefix) error
}

type NetipPrefixValuer interface {
	NetipPrefixValue() (netip.Prefix, error)
}

// InetCodec handles both inet and cidr PostgreSQL types. The preferred Go types are netip.Prefix and netip.Addr. If
// IsValid() is false then they are treated as SQL NULL.
type InetCodec struct{}

func (InetCodec) ( int16) bool {
	return  == TextFormatCode ||  == BinaryFormatCode
}

func (InetCodec) () int16 {
	return BinaryFormatCode
}

func (InetCodec) ( *Map,  uint32,  int16,  any) EncodePlan {
	if ,  := .(NetipPrefixValuer); ! {
		return nil
	}

	switch  {
	case BinaryFormatCode:
		return encodePlanInetCodecBinary{}
	case TextFormatCode:
		return encodePlanInetCodecText{}
	}

	return nil
}

type encodePlanInetCodecBinary struct{}

func (encodePlanInetCodecBinary) ( any,  []byte) ( []byte,  error) {
	,  := .(NetipPrefixValuer).NetipPrefixValue()
	if  != nil {
		return nil, 
	}

	if !.IsValid() {
		return nil, nil
	}

	var  byte
	if .Addr().Is4() {
		 = defaultAFInet
	} else {
		 = defaultAFInet6
	}

	 = append(, )

	 := .Bits()
	 = append(, byte())

	// is_cidr is ignored on server
	 = append(, 0)

	if  == defaultAFInet {
		 = append(, byte(4))
		 := .Addr().As4()
		 = append(, [:]...)
	} else {
		 = append(, byte(16))
		 := .Addr().As16()
		 = append(, [:]...)
	}

	return , nil
}

type encodePlanInetCodecText struct{}

func (encodePlanInetCodecText) ( any,  []byte) ( []byte,  error) {
	,  := .(NetipPrefixValuer).NetipPrefixValue()
	if  != nil {
		return nil, 
	}

	if !.IsValid() {
		return nil, nil
	}

	return append(, .String()...), nil
}

func (InetCodec) ( *Map,  uint32,  int16,  any) ScanPlan {

	switch  {
	case BinaryFormatCode:
		switch .(type) {
		case NetipPrefixScanner:
			return scanPlanBinaryInetToNetipPrefixScanner{}
		}
	case TextFormatCode:
		switch .(type) {
		case NetipPrefixScanner:
			return scanPlanTextAnyToNetipPrefixScanner{}
		}
	}

	return nil
}

func ( InetCodec) ( *Map,  uint32,  int16,  []byte) (driver.Value, error) {
	return codecDecodeToTextFormat(, , , , )
}

func ( InetCodec) ( *Map,  uint32,  int16,  []byte) (any, error) {
	if  == nil {
		return nil, nil
	}

	var  netip.Prefix
	 := codecScan(, , , , , (*netipPrefixWrapper)(&))
	if  != nil {
		return nil, 
	}

	if !.IsValid() {
		return nil, nil
	}

	return , nil
}

type scanPlanBinaryInetToNetipPrefixScanner struct{}

func (scanPlanBinaryInetToNetipPrefixScanner) ( []byte,  any) error {
	 := ().(NetipPrefixScanner)

	if  == nil {
		return .ScanNetipPrefix(netip.Prefix{})
	}

	if len() != 8 && len() != 20 {
		return fmt.Errorf("Received an invalid size for a inet: %d", len())
	}

	// ignore family
	 := [1]
	// ignore is_cidr
	// ignore addressLength - implicit in length of message

	,  := netip.AddrFromSlice([4:])
	if ! {
		return errors.New("netip.AddrFromSlice failed")
	}

	return .ScanNetipPrefix(netip.PrefixFrom(, int()))
}

type scanPlanTextAnyToNetipPrefixScanner struct{}

func (scanPlanTextAnyToNetipPrefixScanner) ( []byte,  any) error {
	 := ().(NetipPrefixScanner)

	if  == nil {
		return .ScanNetipPrefix(netip.Prefix{})
	}

	var  netip.Prefix
	if bytes.IndexByte(, '/') == -1 {
		,  := netip.ParseAddr(string())
		if  != nil {
			return 
		}
		 = netip.PrefixFrom(, .BitLen())
	} else {
		var  error
		,  = netip.ParsePrefix(string())
		if  != nil {
			return 
		}
	}

	return .ScanNetipPrefix()
}