package sms

import (
	"context"
	"encoding/json"
	"fmt"
	"strings"
	"time"

	"github.com/aliyun/alibaba-cloud-sdk-go/sdk"
	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
	"github.com/aliyun/alibaba-cloud-sdk-go/services/dysmsapi"
)

// Config 阿里云短信配置
type Config struct {
	AccessKeyID     string `json:"access_key_id" yaml:"access_key_id"`
	AccessKeySecret string `json:"access_key_secret" yaml:"access_key_secret"`
	Endpoint        string `json:"endpoint" yaml:"endpoint"`
	SignName        string `json:"sign_name" yaml:"sign_name"`
	RetryTimes      int    `json:"retry_times" yaml:"retry_times"`
	Timeout         int    `json:"timeout" yaml:"timeout"`
}

// Service 短信服务接口
type Service interface {
	SendSMS(ctx context.Context, phoneNumbers []string, templateCode string, params map[string]string) error
	SendVerificationCode(ctx context.Context, phoneNumber, templateCode, code string) error
}

// AliYunService 阿里云短信服务实现
type AliYunService struct {
	config    Config
	client    *dysmsapi.Client
	retryTime int
	timeout   time.Duration
}

// NewService 创建阿里云短信服务实例
func NewService(config Config) (Service, error) {
	// 创建配置
	cfg := sdk.NewConfig()
	//cfg.HttpTransport.MaxIdleConns = 100
	//cfg.HttpTransport.IdleConnTimeout = 90 * time.Second
	//cfg.HttpTransport.TLSHandshakeTimeout = 10 * time.Second

	// 默认超时时间
	if config.Timeout <= 0 {
		config.Timeout = 10
	}

	// 默认重试次数
	if config.RetryTimes <= 0 {
		config.RetryTimes = 3
	}

	// 创建凭证
	credential := credentials.NewAccessKeyCredential(
		config.AccessKeyID,
		config.AccessKeySecret,
	)

	// 创建客户端
	client, err := dysmsapi.NewClientWithOptions(
		config.Endpoint,
		cfg,
		credential,
	)

	if err != nil {
		return nil, fmt.Errorf("创建阿里云客户端失败: %w", err)
	}

	return &AliYunService{
		config:    config,
		client:    client,
		retryTime: config.RetryTimes,
		timeout:   time.Duration(config.Timeout) * time.Second,
	}, nil
}

// SendSMS 发送短信
func (s *AliYunService) SendSMS(ctx context.Context, phoneNumbers []string, templateCode string, params map[string]string) error {

	if len(phoneNumbers) == 0 {
		return fmt.Errorf("电话号码不能为空")
	}

	if templateCode == "" {
		return fmt.Errorf("模板代码不能为空")
	}

	// 转换参数为JSON
	paramJSON, err := json.Marshal(params)
	if err != nil {
		return fmt.Errorf("参数序列化失败: %w", err)
	}

	// 创建请求
	request := dysmsapi.CreateSendSmsRequest()
	request.PhoneNumbers = strings.Join(phoneNumbers, ",")
	request.SignName = s.config.SignName
	request.TemplateCode = templateCode
	request.TemplateParam = string(paramJSON)

	// 设置超时
	ctx, cancel := context.WithTimeout(ctx, s.timeout)
	defer cancel()

	// 执行发送（带重试）
	var lastError error
	for i := 0; i <= s.retryTime; i++ {

		if i > 0 {
			// 指数退避重试
			backoff := time.Duration(200*i) * time.Millisecond
			select {
			case <-time.After(backoff):
			case <-ctx.Done():
				return ctx.Err()
			}
		}

		response, err2 := s.client.SendSms(request)
		if err != nil {
			lastError = fmt.Errorf("发送短信失败 (尝试 %d/%d): %w", i+1, s.retryTime+1, err2)
			continue
		}

		if response.Code != "OK" {
			lastError = fmt.Errorf("发送短信失败 (尝试 %d/%d): 代码=%s, 消息=%s,请求=%s",
				i+1, s.retryTime+1, response.Code, response.Message, request.TemplateParam)
			continue
		}

		return nil
	}

	return lastError
}

// SendVerificationCode 发送验证码
func (s *AliYunService) SendVerificationCode(ctx context.Context, phoneNumber, templateCode, code string) error {
	return s.SendSMS(ctx, []string{phoneNumber}, templateCode, map[string]string{"code": code})
}
