package pgtype

import (
	
	
	
	
)

type UUIDScanner interface {
	ScanUUID(v UUID) error
}

type UUIDValuer interface {
	UUIDValue() (UUID, error)
}

type UUID struct {
	Bytes [16]byte
	Valid bool
}

func ( *UUID) ( UUID) error {
	* = 
	return nil
}

func ( UUID) () (UUID, error) {
	return , nil
}

// parseUUID converts a string UUID in standard form to a byte array.
func parseUUID( string) ( [16]byte,  error) {
	switch len() {
	case 36:
		 = [0:8] + [9:13] + [14:18] + [19:23] + [24:]
	case 32:
		// dashes already stripped, assume valid
	default:
		// assume invalid.
		return , fmt.Errorf("cannot parse UUID %v", )
	}

	,  := hex.DecodeString()
	if  != nil {
		return , 
	}

	copy([:], )
	return , 
}

// encodeUUID converts a uuid byte array to UUID standard string form.
func encodeUUID( [16]byte) string {
	return fmt.Sprintf("%x-%x-%x-%x-%x", [0:4], [4:6], [6:8], [8:10], [10:16])
}

// Scan implements the database/sql Scanner interface.
func ( *UUID) ( any) error {
	if  == nil {
		* = UUID{}
		return nil
	}

	switch src := .(type) {
	case string:
		,  := parseUUID()
		if  != nil {
			return 
		}
		* = UUID{Bytes: , Valid: true}
		return nil
	}

	return fmt.Errorf("cannot scan %T", )
}

// Value implements the database/sql/driver Valuer interface.
func ( UUID) () (driver.Value, error) {
	if !.Valid {
		return nil, nil
	}

	return encodeUUID(.Bytes), nil
}

func ( UUID) () ([]byte, error) {
	if !.Valid {
		return []byte("null"), nil
	}

	var  bytes.Buffer
	.WriteByte('"')
	.WriteString(encodeUUID(.Bytes))
	.WriteByte('"')
	return .Bytes(), nil
}

func ( *UUID) ( []byte) error {
	if bytes.Equal(, []byte("null")) {
		* = UUID{}
		return nil
	}
	if len() != 38 {
		return fmt.Errorf("invalid length for UUID: %v", len())
	}
	,  := parseUUID(string([1 : len()-1]))
	if  != nil {
		return 
	}
	* = UUID{Bytes: , Valid: true}
	return nil
}

type UUIDCodec struct{}

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

func (UUIDCodec) () int16 {
	return BinaryFormatCode
}

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

	switch  {
	case BinaryFormatCode:
		return encodePlanUUIDCodecBinaryUUIDValuer{}
	case TextFormatCode:
		return encodePlanUUIDCodecTextUUIDValuer{}
	}

	return nil
}

type encodePlanUUIDCodecBinaryUUIDValuer struct{}

func (encodePlanUUIDCodecBinaryUUIDValuer) ( any,  []byte) ( []byte,  error) {
	,  := .(UUIDValuer).UUIDValue()
	if  != nil {
		return nil, 
	}

	if !.Valid {
		return nil, nil
	}

	return append(, .Bytes[:]...), nil
}

type encodePlanUUIDCodecTextUUIDValuer struct{}

func (encodePlanUUIDCodecTextUUIDValuer) ( any,  []byte) ( []byte,  error) {
	,  := .(UUIDValuer).UUIDValue()
	if  != nil {
		return nil, 
	}

	if !.Valid {
		return nil, nil
	}

	return append(, encodeUUID(.Bytes)...), nil
}

func (UUIDCodec) ( *Map,  uint32,  int16,  any) ScanPlan {
	switch  {
	case BinaryFormatCode:
		switch .(type) {
		case UUIDScanner:
			return scanPlanBinaryUUIDToUUIDScanner{}
		case TextScanner:
			return scanPlanBinaryUUIDToTextScanner{}
		}
	case TextFormatCode:
		switch .(type) {
		case UUIDScanner:
			return scanPlanTextAnyToUUIDScanner{}
		}
	}

	return nil
}

type scanPlanBinaryUUIDToUUIDScanner struct{}

func (scanPlanBinaryUUIDToUUIDScanner) ( []byte,  any) error {
	 := ().(UUIDScanner)

	if  == nil {
		return .ScanUUID(UUID{})
	}

	if len() != 16 {
		return fmt.Errorf("invalid length for UUID: %v", len())
	}

	 := UUID{Valid: true}
	copy(.Bytes[:], )

	return .ScanUUID()
}

type scanPlanBinaryUUIDToTextScanner struct{}

func (scanPlanBinaryUUIDToTextScanner) ( []byte,  any) error {
	 := ().(TextScanner)

	if  == nil {
		return .ScanText(Text{})
	}

	if len() != 16 {
		return fmt.Errorf("invalid length for UUID: %v", len())
	}

	var  [16]byte
	copy([:], )

	return .ScanText(Text{String: encodeUUID(), Valid: true})
}

type scanPlanTextAnyToUUIDScanner struct{}

func (scanPlanTextAnyToUUIDScanner) ( []byte,  any) error {
	 := ().(UUIDScanner)

	if  == nil {
		return .ScanUUID(UUID{})
	}

	,  := parseUUID(string())
	if  != nil {
		return 
	}

	return .ScanUUID(UUID{Bytes: , Valid: true})
}

func ( UUIDCodec) ( *Map,  uint32,  int16,  []byte) (driver.Value, error) {
	if  == nil {
		return nil, nil
	}

	var  UUID
	 := codecScan(, , , , , &)
	if  != nil {
		return nil, 
	}

	return encodeUUID(.Bytes), nil
}

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

	var  UUID
	 := codecScan(, , , , , &)
	if  != nil {
		return nil, 
	}
	return .Bytes, nil
}