package mongo

import (
	"reflect"
	"testing"

	"github.com/shopspring/decimal"
	"github.com/zeromicro/go-zero/core/stores/mon"
)

func TestWithTypeCodec(t *testing.T) {
	// Test creating a TypeCodec
	codec := TypeCodec{
		ValueType: reflect.TypeOf(decimal.Decimal{}),
		Encoder:   &MgoDecimal{},
		Decoder:   &MgoDecimal{},
	}

	if codec.ValueType != reflect.TypeOf(decimal.Decimal{}) {
		t.Errorf("Expected ValueType to be decimal.Decimal, got %v", codec.ValueType)
	}

	if codec.Encoder == nil {
		t.Error("Expected Encoder to be set")
	}

	if codec.Decoder == nil {
		t.Error("Expected Decoder to be set")
	}

	// Test WithTypeCodec function
	option := WithTypeCodec(codec)
	if option == nil {
		t.Error("Expected option to be non-nil")
	}
}

func TestSetCustomDecimalType(t *testing.T) {
	// Test setting custom decimal type
	option := SetCustomDecimalType()

	// Verify that the option is created
	if option == nil {
		t.Error("Expected option to be non-nil")
	}
}

func TestInitMongoOptions(t *testing.T) {
	// Test with default config
	conf := Conf{}
	opts := InitMongoOptions(conf)

	if opts == nil {
		t.Error("Expected options to be non-nil")
	}

	// Test with custom config
	confWithValues := Conf{
		Host:     "localhost:27017",
		Database: "testdb",
		User:     "testuser",
		Password: "testpass",
	}
	optsWithValues := InitMongoOptions(confWithValues)

	if optsWithValues == nil {
		t.Error("Expected options to be non-nil")
	}

	// Test that the options are properly configured
	// We can't directly test the internal configuration, but we can test that it doesn't panic
}

func TestTypeCodec_InterfaceCompliance(t *testing.T) {
	codec := TypeCodec{
		ValueType: reflect.TypeOf(decimal.Decimal{}),
		Encoder:   &MgoDecimal{},
		Decoder:   &MgoDecimal{},
	}

	// Test that the codec can be used
	if codec.ValueType == nil {
		t.Error("Expected ValueType to be set")
	}

	if codec.Encoder == nil {
		t.Error("Expected Encoder to be set")
	}

	if codec.Decoder == nil {
		t.Error("Expected Decoder to be set")
	}
}

func TestMgoDecimal_WithRegistry(t *testing.T) {
	// Test that MgoDecimal can be used with a registry
	option := SetCustomDecimalType()

	// Test that the option is created
	if option == nil {
		t.Error("Expected option to be non-nil")
	}

	// Test basic decimal operations
	dec := decimal.NewFromFloat(123.45)

	// Test that decimal operations work
	if dec.IsZero() {
		t.Error("Expected decimal to be non-zero")
	}

	// Test string conversion
	decStr := dec.String()
	if decStr != "123.45" {
		t.Errorf("Expected '123.45', got '%s'", decStr)
	}
}

func TestInitMongoOptions_WithDifferentConfigs(t *testing.T) {
	testCases := []struct {
		name string
		conf Conf
	}{
		{
			name: "empty config",
			conf: Conf{},
		},
		{
			name: "with host",
			conf: Conf{
				Host: "localhost:27017",
			},
		},
		{
			name: "with database",
			conf: Conf{
				Database: "testdb",
			},
		},
		{
			name: "with credentials",
			conf: Conf{
				User:     "user",
				Password: "pass",
			},
		},
		{
			name: "full config",
			conf: Conf{
				Host:     "localhost:27017",
				Database: "testdb",
				User:     "user",
				Password: "pass",
			},
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			opts := InitMongoOptions(tc.conf)
			if opts == nil {
				t.Error("Expected options to be non-nil")
			}
		})
	}
}

func TestWithTypeCodec_EdgeCases(t *testing.T) {
	// Test with nil encoder
	codec := TypeCodec{
		ValueType: reflect.TypeOf(decimal.Decimal{}),
		Encoder:   nil,
		Decoder:   &MgoDecimal{},
	}

	if codec.Encoder != nil {
		t.Error("Expected Encoder to be nil")
	}

	if codec.Decoder == nil {
		t.Error("Expected Decoder to be set")
	}

	// Test with nil decoder
	codec2 := TypeCodec{
		ValueType: reflect.TypeOf(decimal.Decimal{}),
		Encoder:   &MgoDecimal{},
		Decoder:   nil,
	}

	if codec2.Encoder == nil {
		t.Error("Expected Encoder to be set")
	}

	if codec2.Decoder != nil {
		t.Error("Expected Decoder to be nil")
	}
}

func TestSetCustomDecimalType_MultipleCalls(t *testing.T) {
	// Test calling SetCustomDecimalType multiple times

	// First call
	option1 := SetCustomDecimalType()

	// Second call should not panic
	option2 := SetCustomDecimalType()

	// Options should be valid
	if option1 == nil {
		t.Error("Expected option1 to be non-nil")
	}

	if option2 == nil {
		t.Error("Expected option2 to be non-nil")
	}
}

func TestInitMongoOptions_ReturnType(t *testing.T) {
	conf := Conf{}
	opts := InitMongoOptions(conf)

	// Test that the returned type is correct
	if opts == nil {
		t.Error("Expected options to be non-nil")
	}

	// Test that we can use the options (basic type check)
	var _ mon.Option = opts
}
