package avro

import (
	
	
)

var errNoTypeConverter = errors.New("no type converter")

// TypeConverter represents a data type converter.
type TypeConverter interface {
	// Type returns the Avro data type of the type converter.
	Type() Type

	// LogicalType returns the Avro logical data type of the type converter.
	LogicalType() LogicalType

	// EncodeTypeConvert is the type conversion function called before encoding to Avro.
	EncodeTypeConvert(in any, schema Schema) (any, error)

	// DecodeTypeConvert is the type conversion function called after decoding from Avro.
	DecodeTypeConvert(in any, schema Schema) (any, error)
}

type specificType struct {
	typ Type
	lt  LogicalType
}

// TypeConverters holds the user-provided type conversion functions.
type TypeConverters struct {
	convs sync.Map // map[specificType]TypeConverter
}

// NewTypeConverters creates a new type converter.
func () *TypeConverters {
	return &TypeConverters{}
}

// RegisterTypeConverters registers type converters for converting the data types during encoding and decoding.
func ( *TypeConverters) ( ...TypeConverter) {
	for ,  := range  {
		if  := .Type(); len() == 0 {
			continue
		}
		.convs.Store(specificType{typ: .Type(), lt: .LogicalType()}, )
	}
}

// EncodeTypeConvert runs the encode type conversion function for the given value and schema.
func ( *TypeConverters) ( any,  Schema) (any, error) {
	,  := .getTypeConverter()
	if ! {
		return , errNoTypeConverter
	}

	return .EncodeTypeConvert(, )
}

// DecodeTypeConvert runs the decode type conversion function for the given value and schema.
func ( *TypeConverters) ( any,  Schema) (any, error) {
	,  := .getTypeConverter()
	if ! {
		return , errNoTypeConverter
	}

	return .DecodeTypeConvert(, )
}

func ( *TypeConverters) ( Schema) (TypeConverter, bool) {
	 := .Type()
	 := getLogicalType()
	,  := .convs.Load(specificType{typ: , lt: })
	if ! {
		return nil, false
	}
	return .(TypeConverter), 
}

// RegisterTypeConverters registers type converters for encoding and decoding the data type specified in the converter.
func ( ...TypeConverter) {
	DefaultConfig.RegisterTypeConverters(...)
}

// TypeConversionFuncs is a helper struct to reduce boilerplate in user code.
//
// Implements the TypeConverter interface.
type TypeConversionFuncs struct {
	AvroType              Type
	AvroLogicalType       LogicalType
	EncoderTypeConversion func(in any, schema Schema) (any, error)
	DecoderTypeConversion func(in any, schema Schema) (any, error)
}

// Type returns the Avro data type of the type converter.
func ( TypeConversionFuncs) () Type {
	return .AvroType
}

// LogicalType returns the Avro data type of the type converter.
func ( TypeConversionFuncs) () LogicalType {
	return .AvroLogicalType
}

// EncodeTypeConvert runs the converter's encoder type conversion function if it's set.
func ( TypeConversionFuncs) ( any,  Schema) (any, error) {
	if .EncoderTypeConversion == nil {
		return , errNoTypeConverter
	}
	return .EncoderTypeConversion(, )
}

// DecodeTypeConvert runs the converter's decoder type conversion function if it's set.
func ( TypeConversionFuncs) ( any,  Schema) (any, error) {
	if .DecoderTypeConversion == nil {
		return , errNoTypeConverter
	}
	return .DecoderTypeConversion(, )
}