package schema

import (
	
	
	
	
	
	
	

	
	
	
	
)

type (
	AppenderFunc   func(fmter Formatter, b []byte, v reflect.Value) []byte
	CustomAppender func(typ reflect.Type) AppenderFunc
)

var appenders = []AppenderFunc{
	reflect.Bool:          AppendBoolValue,
	reflect.Int:           AppendIntValue,
	reflect.Int8:          AppendIntValue,
	reflect.Int16:         AppendIntValue,
	reflect.Int32:         AppendIntValue,
	reflect.Int64:         AppendIntValue,
	reflect.Uint:          AppendUintValue,
	reflect.Uint8:         AppendUintValue,
	reflect.Uint16:        AppendUintValue,
	reflect.Uint32:        AppendUintValue,
	reflect.Uint64:        AppendUintValue,
	reflect.Uintptr:       nil,
	reflect.Float32:       AppendFloat32Value,
	reflect.Float64:       AppendFloat64Value,
	reflect.Complex64:     nil,
	reflect.Complex128:    nil,
	reflect.Array:         AppendJSONValue,
	reflect.Chan:          nil,
	reflect.Func:          nil,
	reflect.Interface:     nil,
	reflect.Map:           AppendJSONValue,
	reflect.Ptr:           nil,
	reflect.Slice:         AppendJSONValue,
	reflect.String:        AppendStringValue,
	reflect.Struct:        AppendJSONValue,
	reflect.UnsafePointer: nil,
}

func ( Dialect,  *Field) AppenderFunc {
	if .Tag.HasOption("msgpack") {
		return appendMsgpack
	}

	switch strings.ToUpper(.UserSQLType) {
	case sqltype.JSON, sqltype.JSONB:
		return AppendJSONValue
	}

	return .Appender(.StructField.Type)
}

func ( reflect.Type,  CustomAppender) AppenderFunc {
	switch  {
	case bytesType:
		return appendBytesValue
	case timeType:
		return appendTimeValue
	case ipType:
		return appendIPValue
	case ipNetType:
		return appendIPNetValue
	case jsonRawMessageType:
		return appendJSONRawMessageValue
	}

	if .Implements(queryAppenderType) {
		return appendQueryAppenderValue
	}
	if .Implements(driverValuerType) {
		return driverValueAppender()
	}

	 := .Kind()

	if  != reflect.Ptr {
		 := reflect.PtrTo()
		if .Implements(queryAppenderType) {
			return addrAppender(appendQueryAppenderValue, )
		}
		if .Implements(driverValuerType) {
			return addrAppender(driverValueAppender(), )
		}
	}

	switch  {
	case reflect.Interface:
		return ifaceAppenderFunc(, )
	case reflect.Ptr:
		if  := (.Elem(), );  != nil {
			return PtrAppender()
		}
	case reflect.Slice:
		if .Elem().Kind() == reflect.Uint8 {
			return appendBytesValue
		}
	case reflect.Array:
		if .Elem().Kind() == reflect.Uint8 {
			return appendArrayBytesValue
		}
	}

	if  != nil {
		if  := ();  != nil {
			return 
		}
	}
	return appenders[.Kind()]
}

func ( reflect.Type,  func(reflect.Type) AppenderFunc) AppenderFunc {
	return func( Formatter,  []byte,  reflect.Value) []byte {
		if .IsNil() {
			return dialect.AppendNull()
		}
		 := .Elem()
		 := Appender(.Type(), )
		return (, , )
	}
}

func ( AppenderFunc) AppenderFunc {
	return func( Formatter,  []byte,  reflect.Value) []byte {
		if .IsNil() {
			return dialect.AppendNull()
		}
		return (, , .Elem())
	}
}

func ( Formatter,  []byte,  reflect.Value) []byte {
	return dialect.AppendBool(, .Bool())
}

func ( Formatter,  []byte,  reflect.Value) []byte {
	return strconv.AppendInt(, .Int(), 10)
}

func ( Formatter,  []byte,  reflect.Value) []byte {
	return strconv.AppendUint(, .Uint(), 10)
}

func ( Formatter,  []byte,  reflect.Value) []byte {
	return dialect.AppendFloat32(, float32(.Float()))
}

func ( Formatter,  []byte,  reflect.Value) []byte {
	return dialect.AppendFloat64(, float64(.Float()))
}

func ( Formatter,  []byte,  reflect.Value) []byte {
	return dialect.AppendBytes(, .Bytes())
}

func ( Formatter,  []byte,  reflect.Value) []byte {
	if .CanAddr() {
		return dialect.AppendBytes(, .Slice(0, .Len()).Bytes())
	}

	 := make([]byte, .Len())
	reflect.Copy(reflect.ValueOf(), )
	 = dialect.AppendBytes(, )
	return 
}

func ( Formatter,  []byte,  reflect.Value) []byte {
	return dialect.AppendString(, .String())
}

func ( Formatter,  []byte,  reflect.Value) []byte {
	,  := bunjson.Marshal(.Interface())
	if  != nil {
		return dialect.AppendError(, )
	}

	if len() > 0 && [len()-1] == '\n' {
		 = [:len()-1]
	}

	return dialect.AppendJSON(, )
}

func ( Formatter,  []byte,  reflect.Value) []byte {
	 := .Interface().(time.Time)
	return dialect.AppendTime(, )
}

func ( Formatter,  []byte,  reflect.Value) []byte {
	 := .Interface().(net.IP)
	return dialect.AppendString(, .String())
}

func ( Formatter,  []byte,  reflect.Value) []byte {
	 := .Interface().(net.IPNet)
	return dialect.AppendString(, .String())
}

func ( Formatter,  []byte,  reflect.Value) []byte {
	 := .Bytes()
	if  == nil {
		return dialect.AppendNull()
	}
	return dialect.AppendString(, internal.String())
}

func ( Formatter,  []byte,  reflect.Value) []byte {
	return AppendQueryAppender(, , .Interface().(QueryAppender))
}

func ( CustomAppender) AppenderFunc {
	return func( Formatter,  []byte,  reflect.Value) []byte {
		return appendDriverValue(, , .Interface().(driver.Valuer), )
	}
}

func ( Formatter,  []byte,  driver.Valuer,  CustomAppender) []byte {
	,  := .Value()
	if  != nil {
		return dialect.AppendError(, )
	}
	return Append(, , , )
}

func ( AppenderFunc,  CustomAppender) AppenderFunc {
	return func( Formatter,  []byte,  reflect.Value) []byte {
		if !.CanAddr() {
			 := fmt.Errorf("bun: Append(nonaddressable %T)", .Interface())
			return dialect.AppendError(, )
		}
		return (, , .Addr())
	}
}