package avro

import (
	
	
	
	
	

	
)

func createDecoderOfRecord( *decoderContext,  Schema,  reflect2.Type) ValDecoder {
	switch .Kind() {
	case reflect.Struct:
		return decoderOfStruct(, , )

	case reflect.Map:
		if .(reflect2.MapType).Key().Kind() != reflect.String ||
			.(reflect2.MapType).Elem().Kind() != reflect.Interface {
			break
		}
		return decoderOfRecord(, , )

	case reflect.Ptr:
		return decoderOfPtr(, , )

	case reflect.Interface:
		if ,  := .(*reflect2.UnsafeIFaceType);  {
			return &recordIfaceDecoder{schema: , valType: }
		}
	}

	return &errorDecoder{err: fmt.Errorf("avro: %s is unsupported for avro %s", .String(), .Type())}
}

func createEncoderOfRecord( *encoderContext,  *RecordSchema,  reflect2.Type) ValEncoder {
	switch .Kind() {
	case reflect.Struct:
		return encoderOfStruct(, , )

	case reflect.Map:
		if .(reflect2.MapType).Key().Kind() != reflect.String ||
			.(reflect2.MapType).Elem().Kind() != reflect.Interface {
			break
		}
		return encoderOfRecord(, , )

	case reflect.Ptr:
		return encoderOfPtr(, , )
	}

	return &errorEncoder{err: fmt.Errorf("avro: %s is unsupported for avro %s", .String(), .Type())}
}

func decoderOfStruct( *decoderContext,  Schema,  reflect2.Type) ValDecoder {
	 := .(*RecordSchema)
	 := describeStruct(.cfg.getTagKey(), )

	 := make([]*structFieldDecoder, 0, len(.Fields()))

	for ,  := range .Fields() {
		if .action == FieldIgnore {
			 = append(, &structFieldDecoder{
				decoder: createSkipDecoder(.Type()),
			})
			continue
		}

		 := .Fields.Get(.Name())
		if  == nil {
			for ,  := range .Aliases() {
				 = .Fields.Get()
				if  != nil {
					break
				}
			}
		}
		// Skip field if it doesn't exist
		if  == nil {
			// If the field value doesn't exist in the binary, ignore it instead of
			// appending a 'SkipDecoder'.
			//
			// Note: 'SkipDecoder' performs a read and moves the cursor, which,
			// in this case, will lead to a dirty read.
			if .action == FieldSetDefault {
				continue
			}

			 = append(, &structFieldDecoder{
				decoder: createSkipDecoder(.Type()),
			})
			continue
		}

		if .action == FieldSetDefault {
			if .hasDef {
				 = append(, &structFieldDecoder{
					field:   .Field,
					decoder: createDefaultDecoder(, , .Field[len(.Field)-1].Type()),
				})

				continue
			}
		}

		 := decoderOfType(, .Type(), .Field[len(.Field)-1].Type())
		 = append(, &structFieldDecoder{
			field:   .Field,
			decoder: ,
		})
	}

	return &structDecoder{typ: , fields: }
}

type structFieldDecoder struct {
	field   []*reflect2.UnsafeStructField
	decoder ValDecoder
}

type structDecoder struct {
	typ    reflect2.Type
	fields []*structFieldDecoder
}

func ( *structDecoder) ( unsafe.Pointer,  *Reader) {
	for ,  := range .fields {
		// Skip case
		if .field == nil {
			.decoder.Decode(nil, )
			continue
		}

		 := 
		for ,  := range .field {
			 = .UnsafeGet()

			if  == len(.field)-1 {
				break
			}

			if .Type().Kind() == reflect.Ptr {
				if *((*unsafe.Pointer)()) == nil {
					 := .Type().(*reflect2.UnsafePtrType).Elem().UnsafeNew()
					*((*unsafe.Pointer)()) = 
				}

				 = *((*unsafe.Pointer)())
			}
		}
		.decoder.Decode(, )

		if .Error != nil && !errors.Is(.Error, io.EOF) {
			for ,  := range .field {
				.Error = fmt.Errorf("%s: %w", .Name(), .Error)
				return
			}
		}
	}
}

func encoderOfStruct( *encoderContext,  *RecordSchema,  reflect2.Type) ValEncoder {
	 := describeStruct(.cfg.getTagKey(), )

	 := make([]*structFieldEncoder, 0, len(.Fields()))
	for ,  := range .Fields() {
		 := .Fields.Get(.Name())
		if  != nil {
			 = append(, &structFieldEncoder{
				field:   .Field,
				encoder: encoderOfType(, .Type(), .Field[len(.Field)-1].Type()),
			})
			continue
		}

		if !.HasDefault() {
			// In all other cases, this is a required field
			 := fmt.Errorf("avro: record %s is missing required field %q", .FullName(), .Name())
			return &errorEncoder{err: }
		}

		 := .Default()
		if .Default() == nil {
			if .Type().Type() == Null {
				// We write nothing in a Null case, just skip it
				continue
			}

			if .Type().Type() == Union && .Type().(*UnionSchema).Nullable() {
				 := reflect2.TypeOf(&)
				 = append(, &structFieldEncoder{
					defaultPtr: reflect2.PtrOf(&),
					encoder:    encoderOfNullableUnion(, .Type(), ),
				})
				continue
			}
		}

		 := reflect2.TypeOf()
		 := encoderOfType(, .Type(), )
		if .LikePtr() {
			 = &onePtrEncoder{}
		}
		 = append(, &structFieldEncoder{
			defaultPtr: reflect2.PtrOf(),
			encoder:    ,
		})
	}
	return &structEncoder{typ: , fields: }
}

type structFieldEncoder struct {
	field      []*reflect2.UnsafeStructField
	defaultPtr unsafe.Pointer
	encoder    ValEncoder
}

type structEncoder struct {
	typ    reflect2.Type
	fields []*structFieldEncoder
}

func ( *structEncoder) ( unsafe.Pointer,  *Writer) {
	for ,  := range .fields {
		// Default case
		if .field == nil {
			.encoder.Encode(.defaultPtr, )
			continue
		}

		 := 
		for ,  := range .field {
			 = .UnsafeGet()

			if  == len(.field)-1 {
				break
			}

			if .Type().Kind() == reflect.Ptr {
				if *((*unsafe.Pointer)()) == nil {
					.Error = fmt.Errorf("embedded field %q is nil", .Name())
					return
				}

				 = *((*unsafe.Pointer)())
			}
		}
		.encoder.Encode(, )

		if .Error != nil && !errors.Is(.Error, io.EOF) {
			for ,  := range .field {
				.Error = fmt.Errorf("%s: %w", .Name(), .Error)
				return
			}
		}
	}
}

func decoderOfRecord( *decoderContext,  Schema,  reflect2.Type) ValDecoder {
	 := .(*RecordSchema)
	 := .(*reflect2.UnsafeMapType)

	 := make([]recordMapDecoderField, len(.Fields()))
	for ,  := range .Fields() {
		switch .action {
		case FieldIgnore:
			[] = recordMapDecoderField{
				name:    .Name(),
				decoder: createSkipDecoder(.Type()),
				skip:    true,
			}
			continue
		case FieldSetDefault:
			if .hasDef {
				[] = recordMapDecoderField{
					name:    .Name(),
					decoder: createDefaultDecoder(, , .Elem()),
				}
				continue
			}
		}

		[] = recordMapDecoderField{
			name:    .Name(),
			decoder: decoderOfType(, .Type(), .Elem()),
		}
	}

	return &recordMapDecoder{
		mapType:  ,
		elemType: .Elem(),
		fields:   ,
	}
}

type recordMapDecoderField struct {
	name    string
	decoder ValDecoder
	skip    bool
}

type recordMapDecoder struct {
	mapType  *reflect2.UnsafeMapType
	elemType reflect2.Type
	fields   []recordMapDecoderField
}

func ( *recordMapDecoder) ( unsafe.Pointer,  *Reader) {
	if .mapType.UnsafeIsNil() {
		.mapType.UnsafeSet(, .mapType.UnsafeMakeMap(len(.fields)))
	}

	for ,  := range .fields {
		 := .elemType.UnsafeNew()
		.decoder.Decode(, )
		if .skip {
			continue
		}

		.mapType.UnsafeSetIndex(, reflect2.PtrOf(), )
	}

	if .Error != nil && !errors.Is(.Error, io.EOF) {
		.Error = fmt.Errorf("%v: %w", .mapType, .Error)
	}
}

func encoderOfRecord( *encoderContext,  *RecordSchema,  reflect2.Type) ValEncoder {
	 := .(*reflect2.UnsafeMapType)

	 := make([]mapEncoderField, len(.Fields()))
	for ,  := range .Fields() {
		[] = mapEncoderField{
			name:    .Name(),
			hasDef:  .HasDefault(),
			def:     .Default(),
			encoder: encoderOfType(, .Type(), .Elem()),
		}

		if .HasDefault() {
			switch {
			case .Type().Type() == Union:
				 := .Type().(*UnionSchema)
				[].def = map[string]any{
					string(.Types()[0].Type()): .Default(),
				}
			case .Default() == nil:
				continue
			}

			 := reflect2.TypeOf([].def)
			[].defEncoder = encoderOfType(, .Type(), )
			if .LikePtr() {
				[].defEncoder = &onePtrEncoder{[].defEncoder}
			}
		}
	}

	return &recordMapEncoder{
		mapType: ,
		fields:  ,
	}
}

type mapEncoderField struct {
	name       string
	hasDef     bool
	def        any
	defEncoder ValEncoder
	encoder    ValEncoder
}

type recordMapEncoder struct {
	mapType *reflect2.UnsafeMapType
	fields  []mapEncoderField
}

func ( *recordMapEncoder) ( unsafe.Pointer,  *Writer) {
	for ,  := range .fields {
		// The first property of mapEncoderField is the name, so a pointer
		// to field is a pointer to the name.
		 := .mapType.UnsafeGetIndex(, reflect2.PtrOf())
		if  == nil {
			// Missing required field
			if !.hasDef {
				.Error = fmt.Errorf("avro: missing required field %s", .name)
				return
			}

			// Null default
			if .def == nil {
				continue
			}

			 := reflect2.PtrOf(.def)
			.defEncoder.Encode(, )
			continue
		}

		.encoder.Encode(, )

		if .Error != nil && !errors.Is(.Error, io.EOF) {
			.Error = fmt.Errorf("%s: %w", .name, .Error)
			return
		}
	}
}

type recordIfaceDecoder struct {
	schema  Schema
	valType *reflect2.UnsafeIFaceType
}

func ( *recordIfaceDecoder) ( unsafe.Pointer,  *Reader) {
	 := .valType.UnsafeIndirect()
	if reflect2.IsNil() {
		.ReportError("decode non empty interface", "can not unmarshal into nil")
		return
	}

	.ReadVal(.schema, )
}

type structDescriptor struct {
	Type   reflect2.Type
	Fields structFields
}

type structFields []*structField

func ( structFields) ( string) *structField {
	for ,  := range  {
		if .Name ==  {
			return 
		}
	}

	return nil
}

type structField struct {
	Name  string
	Field []*reflect2.UnsafeStructField

	anon *reflect2.UnsafeStructType
}

func describeStruct( string,  reflect2.Type) *structDescriptor {
	 := .(*reflect2.UnsafeStructType)
	 := structFields{}

	var  []structField
	 := []structField{{anon: }}

	 := map[uintptr]bool{}

	for len() > 0 {
		,  = , [:0]

		for ,  := range  {
			 := .anon.RType()
			if [.anon.RType()] {
				continue
			}
			[] = true

			for  := range .anon.NumField() {
				 := .anon.Field().(*reflect2.UnsafeStructField)
				 := .PkgPath() != ""

				 := make([]*reflect2.UnsafeStructField, len(.Field)+1)
				copy(, .Field)
				[len(.Field)] = 

				if .Anonymous() {
					 := .Type()
					if .Kind() == reflect.Ptr {
						 = .(*reflect2.UnsafePtrType).Elem()
					}
					if .Kind() != reflect.Struct {
						continue
					}

					 = append(, structField{Field: , anon: .(*reflect2.UnsafeStructType)})
					continue
				}

				// Ignore unexported fields.
				if  {
					continue
				}

				 := .Name()
				if ,  := .Tag().Lookup();  {
					 = 
				}

				 = append(, &structField{
					Name:  ,
					Field: ,
				})
			}
		}
	}

	return &structDescriptor{
		Type:   ,
		Fields: ,
	}
}