package config

import (
	"errors"
	"fmt"
	"time"
)

type SMTPConfig struct {
	Enable           bool
	Sort             int
	GoroutinePoolNum int

	Host     string
	Port     int
	Username string
	Password string
}

// Validate 驗證 SMTP 配置
func (c *SMTPConfig) Validate() error {
	if !c.Enable {
		return nil // 未啟用則不驗證
	}

	if c.Host == "" {
		return errors.New("smtp host is required")
	}

	if c.Port <= 0 || c.Port > 65535 {
		return fmt.Errorf("smtp port must be between 1 and 65535, got %d", c.Port)
	}

	if c.Username == "" {
		return errors.New("smtp username is required")
	}

	if c.Password == "" {
		return errors.New("smtp password is required")
	}

	if c.Sort < 0 {
		return fmt.Errorf("smtp sort must be >= 0, got %d", c.Sort)
	}

	return nil
}

type AmazonSesSettings struct {
	Enable   bool
	Sort     int
	PoolSize int

	Region    string
	Sender    string
	Charset   string
	AccessKey string
	SecretKey string
	Token     string
}

// Validate 驗證 AWS SES 配置
func (c *AmazonSesSettings) Validate() error {
	if !c.Enable {
		return nil // 未啟用則不驗證
	}

	if c.Region == "" {
		return errors.New("aws ses region is required")
	}

	if c.Sender == "" {
		return errors.New("aws ses sender is required")
	}

	if c.AccessKey == "" {
		return errors.New("aws ses access key is required")
	}

	if c.SecretKey == "" {
		return errors.New("aws ses secret key is required")
	}

	if c.Sort < 0 {
		return fmt.Errorf("aws ses sort must be >= 0, got %d", c.Sort)
	}

	if c.PoolSize < 0 {
		return fmt.Errorf("aws ses pool size must be >= 0, got %d", c.PoolSize)
	}

	return nil
}

type MitakeSMSSender struct {
	Enable   bool
	Sort     int
	PoolSize int

	User     string
	Password string
}

// Validate 驗證 Mitake SMS 配置
func (c *MitakeSMSSender) Validate() error {
	if !c.Enable {
		return nil // 未啟用則不驗證
	}

	if c.User == "" {
		return errors.New("mitake user is required")
	}

	if c.Password == "" {
		return errors.New("mitake password is required")
	}

	if c.Sort < 0 {
		return fmt.Errorf("mitake sort must be >= 0, got %d", c.Sort)
	}

	if c.PoolSize < 0 {
		return fmt.Errorf("mitake pool size must be >= 0, got %d", c.PoolSize)
	}

	return nil
}

// DeliveryConfig 傳送重試配置
type DeliveryConfig struct {
	MaxRetries    int           `json:"max_retries"`    // 最大重試次數
	InitialDelay  time.Duration `json:"initial_delay"`  // 初始重試延遲 (100ms)
	BackoffFactor float64       `json:"backoff_factor"` // 指數退避因子 (2.0)
	MaxDelay      time.Duration `json:"max_delay"`      // 最大延遲時間
	Timeout       time.Duration `json:"timeout"`        // 單次發送超時時間
	EnableHistory bool          `json:"enable_history"` // 是否啟用歷史記錄
}

// Validate 驗證 DeliveryConfig 配置
func (c *DeliveryConfig) Validate() error {
	if c.MaxRetries < 0 {
		return fmt.Errorf("max_retries must be >= 0, got %d", c.MaxRetries)
	}

	if c.MaxRetries > 10 {
		return fmt.Errorf("max_retries should not exceed 10, got %d", c.MaxRetries)
	}

	if c.InitialDelay < 0 {
		return fmt.Errorf("initial_delay must be >= 0, got %v", c.InitialDelay)
	}

	if c.InitialDelay > 10*time.Second {
		return fmt.Errorf("initial_delay is too large (> 10s), got %v", c.InitialDelay)
	}

	if c.BackoffFactor < 1.0 {
		return fmt.Errorf("backoff_factor must be >= 1.0, got %v", c.BackoffFactor)
	}

	if c.BackoffFactor > 10.0 {
		return fmt.Errorf("backoff_factor is too large (> 10.0), got %v", c.BackoffFactor)
	}

	if c.MaxDelay < 0 {
		return fmt.Errorf("max_delay must be >= 0, got %v", c.MaxDelay)
	}

	if c.MaxDelay > 5*time.Minute {
		return fmt.Errorf("max_delay is too large (> 5m), got %v", c.MaxDelay)
	}

	if c.Timeout <= 0 {
		return fmt.Errorf("timeout must be > 0, got %v", c.Timeout)
	}

	if c.Timeout > 5*time.Minute {
		return fmt.Errorf("timeout is too large (> 5m), got %v", c.Timeout)
	}

	// 檢查 InitialDelay 和 MaxDelay 的關係
	if c.InitialDelay > c.MaxDelay && c.MaxDelay > 0 {
		return fmt.Errorf("initial_delay (%v) should not exceed max_delay (%v)", c.InitialDelay, c.MaxDelay)
	}

	return nil
}

// SetDefaults 設置默認值
func (c *DeliveryConfig) SetDefaults() {
	if c.MaxRetries == 0 {
		c.MaxRetries = 3
	}
	if c.InitialDelay == 0 {
		c.InitialDelay = 100 * time.Millisecond
	}
	if c.BackoffFactor == 0 {
		c.BackoffFactor = 2.0
	}
	if c.MaxDelay == 0 {
		c.MaxDelay = 30 * time.Second
	}
	if c.Timeout == 0 {
		c.Timeout = 30 * time.Second
	}
}
