package pgtype

import (
	
	
	
	
	
	
)

type BoolScanner interface {
	ScanBool(v Bool) error
}

type BoolValuer interface {
	BoolValue() (Bool, error)
}

type Bool struct {
	Bool  bool
	Valid bool
}

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

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

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

	switch src := .(type) {
	case bool:
		* = Bool{Bool: , Valid: true}
		return nil
	case string:
		,  := strconv.ParseBool()
		if  != nil {
			return 
		}
		* = Bool{Bool: , Valid: true}
		return nil
	case []byte:
		,  := strconv.ParseBool(string())
		if  != nil {
			return 
		}
		* = Bool{Bool: , Valid: true}
		return nil
	}

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

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

	return .Bool, nil
}

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

	if .Bool {
		return []byte("true"), nil
	} else {
		return []byte("false"), nil
	}
}

func ( *Bool) ( []byte) error {
	var  *bool
	 := json.Unmarshal(, &)
	if  != nil {
		return 
	}

	if  == nil {
		* = Bool{}
	} else {
		* = Bool{Bool: *, Valid: true}
	}

	return nil
}

type BoolCodec struct{}

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

func (BoolCodec) () int16 {
	return BinaryFormatCode
}

func (BoolCodec) ( *Map,  uint32,  int16,  any) EncodePlan {
	switch  {
	case BinaryFormatCode:
		switch .(type) {
		case bool:
			return encodePlanBoolCodecBinaryBool{}
		case BoolValuer:
			return encodePlanBoolCodecBinaryBoolValuer{}
		}
	case TextFormatCode:
		switch .(type) {
		case bool:
			return encodePlanBoolCodecTextBool{}
		case BoolValuer:
			return encodePlanBoolCodecTextBoolValuer{}
		}
	}

	return nil
}

type encodePlanBoolCodecBinaryBool struct{}

func (encodePlanBoolCodecBinaryBool) ( any,  []byte) ( []byte,  error) {
	 := .(bool)

	if  {
		 = append(, 1)
	} else {
		 = append(, 0)
	}

	return , nil
}

type encodePlanBoolCodecTextBoolValuer struct{}

func (encodePlanBoolCodecTextBoolValuer) ( any,  []byte) ( []byte,  error) {
	,  := .(BoolValuer).BoolValue()
	if  != nil {
		return nil, 
	}

	if !.Valid {
		return nil, nil
	}

	if .Bool {
		 = append(, 't')
	} else {
		 = append(, 'f')
	}

	return , nil
}

type encodePlanBoolCodecBinaryBoolValuer struct{}

func (encodePlanBoolCodecBinaryBoolValuer) ( any,  []byte) ( []byte,  error) {
	,  := .(BoolValuer).BoolValue()
	if  != nil {
		return nil, 
	}

	if !.Valid {
		return nil, nil
	}

	if .Bool {
		 = append(, 1)
	} else {
		 = append(, 0)
	}

	return , nil
}

type encodePlanBoolCodecTextBool struct{}

func (encodePlanBoolCodecTextBool) ( any,  []byte) ( []byte,  error) {
	 := .(bool)

	if  {
		 = append(, 't')
	} else {
		 = append(, 'f')
	}

	return , nil
}

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

	switch  {
	case BinaryFormatCode:
		switch .(type) {
		case *bool:
			return scanPlanBinaryBoolToBool{}
		case BoolScanner:
			return scanPlanBinaryBoolToBoolScanner{}
		}
	case TextFormatCode:
		switch .(type) {
		case *bool:
			return scanPlanTextAnyToBool{}
		case BoolScanner:
			return scanPlanTextAnyToBoolScanner{}
		}
	}

	return nil
}

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

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

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

type scanPlanBinaryBoolToBool struct{}

func (scanPlanBinaryBoolToBool) ( []byte,  any) error {
	if  == nil {
		return fmt.Errorf("cannot scan NULL into %T", )
	}

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

	,  := ().(*bool)
	if ! {
		return ErrScanTargetTypeChanged
	}

	* = [0] == 1

	return nil
}

type scanPlanTextAnyToBool struct{}

func (scanPlanTextAnyToBool) ( []byte,  any) error {
	if  == nil {
		return fmt.Errorf("cannot scan NULL into %T", )
	}

	if len() == 0 {
		return fmt.Errorf("cannot scan empty string into %T", )
	}

	,  := ().(*bool)
	if ! {
		return ErrScanTargetTypeChanged
	}

	,  := planTextToBool()
	if  != nil {
		return 
	}

	* = 

	return nil
}

type scanPlanBinaryBoolToBoolScanner struct{}

func (scanPlanBinaryBoolToBoolScanner) ( []byte,  any) error {
	,  := ().(BoolScanner)
	if ! {
		return ErrScanTargetTypeChanged
	}

	if  == nil {
		return .ScanBool(Bool{})
	}

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

	return .ScanBool(Bool{Bool: [0] == 1, Valid: true})
}

type scanPlanTextAnyToBoolScanner struct{}

func (scanPlanTextAnyToBoolScanner) ( []byte,  any) error {
	,  := ().(BoolScanner)
	if ! {
		return ErrScanTargetTypeChanged
	}

	if  == nil {
		return .ScanBool(Bool{})
	}

	if len() == 0 {
		return fmt.Errorf("cannot scan empty string into %T", )
	}

	,  := planTextToBool()
	if  != nil {
		return 
	}

	return .ScanBool(Bool{Bool: , Valid: true})
}

// https://www.postgresql.org/docs/11/datatype-boolean.html
func planTextToBool( []byte) (bool, error) {
	 := string(bytes.ToLower(bytes.TrimSpace()))

	switch {
	case strings.HasPrefix("true", ), strings.HasPrefix("yes", ),  == "on",  == "1":
		return true, nil
	case strings.HasPrefix("false", ), strings.HasPrefix("no", ), strings.HasPrefix("off", ),  == "0":
		return false, nil
	default:
		return false, fmt.Errorf("unknown boolean string representation %q", )
	}
}