package config

import (
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
)

func TestSMTPConfig_Validate(t *testing.T) {
	tests := []struct {
		name    string
		config  SMTPConfig
		wantErr bool
		errMsg  string
	}{
		{
			name: "有效的 SMTP 配置",
			config: SMTPConfig{
				Enable:   true,
				Sort:     1,
				Host:     "smtp.gmail.com",
				Port:     587,
				Username: "test@gmail.com",
				Password: "password",
			},
			wantErr: false,
		},
		{
			name: "未啟用的配置（不驗證）",
			config: SMTPConfig{
				Enable: false,
			},
			wantErr: false,
		},
		{
			name: "缺少 Host",
			config: SMTPConfig{
				Enable:   true,
				Port:     587,
				Username: "test@gmail.com",
				Password: "password",
			},
			wantErr: true,
			errMsg:  "smtp host is required",
		},
		{
			name: "無效的 Port",
			config: SMTPConfig{
				Enable:   true,
				Host:     "smtp.gmail.com",
				Port:     99999,
				Username: "test@gmail.com",
				Password: "password",
			},
			wantErr: true,
			errMsg:  "smtp port must be between 1 and 65535",
		},
		{
			name: "缺少 Username",
			config: SMTPConfig{
				Enable:   true,
				Host:     "smtp.gmail.com",
				Port:     587,
				Password: "password",
			},
			wantErr: true,
			errMsg:  "smtp username is required",
		},
		{
			name: "負數的 Sort",
			config: SMTPConfig{
				Enable:   true,
				Sort:     -1,
				Host:     "smtp.gmail.com",
				Port:     587,
				Username: "test@gmail.com",
				Password: "password",
			},
			wantErr: true,
			errMsg:  "smtp sort must be >= 0",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := tt.config.Validate()
			if tt.wantErr {
				assert.Error(t, err)
				if tt.errMsg != "" {
					assert.Contains(t, err.Error(), tt.errMsg)
				}
			} else {
				assert.NoError(t, err)
			}
		})
	}
}

func TestAmazonSesSettings_Validate(t *testing.T) {
	tests := []struct {
		name    string
		config  AmazonSesSettings
		wantErr bool
		errMsg  string
	}{
		{
			name: "有效的 AWS SES 配置",
			config: AmazonSesSettings{
				Enable:    true,
				Sort:      1,
				PoolSize:  10,
				Region:    "us-west-2",
				Sender:    "noreply@example.com",
				AccessKey: "AKIAIOSFODNN7EXAMPLE",
				SecretKey: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
			},
			wantErr: false,
		},
		{
			name: "未啟用的配置",
			config: AmazonSesSettings{
				Enable: false,
			},
			wantErr: false,
		},
		{
			name: "缺少 Region",
			config: AmazonSesSettings{
				Enable:    true,
				Sender:    "noreply@example.com",
				AccessKey: "AKIAIOSFODNN7EXAMPLE",
				SecretKey: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
			},
			wantErr: true,
			errMsg:  "aws ses region is required",
		},
		{
			name: "缺少 AccessKey",
			config: AmazonSesSettings{
				Enable:    true,
				Region:    "us-west-2",
				Sender:    "noreply@example.com",
				SecretKey: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
			},
			wantErr: true,
			errMsg:  "aws ses access key is required",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := tt.config.Validate()
			if tt.wantErr {
				assert.Error(t, err)
				if tt.errMsg != "" {
					assert.Contains(t, err.Error(), tt.errMsg)
				}
			} else {
				assert.NoError(t, err)
			}
		})
	}
}

func TestMitakeSMSSender_Validate(t *testing.T) {
	tests := []struct {
		name    string
		config  MitakeSMSSender
		wantErr bool
		errMsg  string
	}{
		{
			name: "有效的 Mitake 配置",
			config: MitakeSMSSender{
				Enable:   true,
				Sort:     1,
				PoolSize: 5,
				User:     "testuser",
				Password: "testpass",
			},
			wantErr: false,
		},
		{
			name: "缺少 User",
			config: MitakeSMSSender{
				Enable:   true,
				Password: "testpass",
			},
			wantErr: true,
			errMsg:  "mitake user is required",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := tt.config.Validate()
			if tt.wantErr {
				assert.Error(t, err)
				if tt.errMsg != "" {
					assert.Contains(t, err.Error(), tt.errMsg)
				}
			} else {
				assert.NoError(t, err)
			}
		})
	}
}

func TestDeliveryConfig_Validate(t *testing.T) {
	tests := []struct {
		name    string
		config  DeliveryConfig
		wantErr bool
		errMsg  string
	}{
		{
			name: "有效的配置",
			config: DeliveryConfig{
				MaxRetries:    3,
				InitialDelay:  100 * time.Millisecond,
				BackoffFactor: 2.0,
				MaxDelay:      30 * time.Second,
				Timeout:       30 * time.Second,
			},
			wantErr: false,
		},
		{
			name: "MaxRetries 為負數",
			config: DeliveryConfig{
				MaxRetries: -1,
				Timeout:    30 * time.Second,
			},
			wantErr: true,
			errMsg:  "max_retries must be >= 0",
		},
		{
			name: "MaxRetries 過大",
			config: DeliveryConfig{
				MaxRetries: 20,
				Timeout:    30 * time.Second,
			},
			wantErr: true,
			errMsg:  "max_retries should not exceed 10",
		},
		{
			name: "BackoffFactor 小於 1.0",
			config: DeliveryConfig{
				MaxRetries:    3,
				BackoffFactor: 0.5,
				Timeout:       30 * time.Second,
			},
			wantErr: true,
			errMsg:  "backoff_factor must be >= 1.0",
		},
		{
			name: "Timeout 為 0",
			config: DeliveryConfig{
				MaxRetries:    3,
				BackoffFactor: 2.0,
				Timeout:       0,
			},
			wantErr: true,
			errMsg:  "timeout must be > 0",
		},
		{
			name: "InitialDelay 大於 MaxDelay",
			config: DeliveryConfig{
				MaxRetries:   3,
				InitialDelay: 1 * time.Minute,
				MaxDelay:     10 * time.Second,
				Timeout:      30 * time.Second,
			},
			wantErr: true,
			errMsg:  "initial_delay",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := tt.config.Validate()
			if tt.wantErr {
				assert.Error(t, err)
				if tt.errMsg != "" {
					assert.Contains(t, err.Error(), tt.errMsg)
				}
			} else {
				assert.NoError(t, err)
			}
		})
	}
}

func TestDeliveryConfig_SetDefaults(t *testing.T) {
	config := DeliveryConfig{}
	config.SetDefaults()

	assert.Equal(t, 3, config.MaxRetries)
	assert.Equal(t, 100*time.Millisecond, config.InitialDelay)
	assert.Equal(t, 2.0, config.BackoffFactor)
	assert.Equal(t, 30*time.Second, config.MaxDelay)
	assert.Equal(t, 30*time.Second, config.Timeout)

	// 測試不覆蓋已設置的值
	config2 := DeliveryConfig{
		MaxRetries: 5,
		Timeout:    60 * time.Second,
	}
	config2.SetDefaults()

	assert.Equal(t, 5, config2.MaxRetries)                      // 保持原值
	assert.Equal(t, 60*time.Second, config2.Timeout)            // 保持原值
	assert.Equal(t, 100*time.Millisecond, config2.InitialDelay) // 設置默認值
}
