package sms

import (
	"fmt"
	"time"

	"github.com/veypi/vbase/cfg"
	"github.com/veypi/vbase/libs/sms_providers"
	"github.com/veypi/vbase/libs/utils"
	"github.com/veypi/vbase/models"
	"github.com/veypi/vigo"
	"github.com/veypi/vigo/contrib/limiter"
	"gorm.io/gorm"
)

// SendCodeRequest 发送验证码请求
type SendCodeRequest struct {
	Phone      string `json:"phone" src:"json" desc:"手机号"`
	Region     string `json:"region" src:"json" desc:"区域"`
	Purpose    string `json:"purpose" src:"json" desc:"用途"`
	TemplateID string `json:"template_id" src:"json" desc:"模板ID"`
}

// SendCodeResponse 发送验证码响应
type SendCodeResponse struct {
	ID        string    `json:"id"`
	Phone     string    `json:"phone"`
	ExpiresAt time.Time `json:"expires_at"`
	Interval  int       `json:"interval"` // 下次可发送间隔（秒）
}

var _ = Router.Post("/", "发送验证码", vigo.SkipBefore, limiter.NewAdvancedRequestLimiter(time.Minute*3, 5, time.Second*30).Limit, sendCode)

// SendCode 发送验证码
func sendCode(x *vigo.X, req *SendCodeRequest) (*SendCodeResponse, error) {
	// 1. 验证手机号
	normalizedPhone := utils.NormalizePhoneNumber(req.Phone)
	if !utils.ValidatePhoneNumber(normalizedPhone) {
		return nil, fmt.Errorf("invalid phone number: %s", req.Phone)
	}

	// 2. 检查区域配置
	provider, err := sms_providers.GetSMSProvider(req.Region)
	if err != nil {
		return nil, err
	}

	// 3. 检查发送频率限制
	if err := CheckSendInterval(normalizedPhone, req.Region, req.Purpose); err != nil {
		return nil, err
	}

	// 4. 检查每日发送次数限制
	if err := CheckDailyLimit(normalizedPhone, req.Region); err != nil {
		return nil, err
	}

	// 5. 生成验证码
	code, err := utils.GenerateCode(cfg.Config.SMS.Global.CodeLength)
	if err != nil {
		return nil, fmt.Errorf("failed to generate code: %w", err)
	}

	// 6. 创建验证码记录
	smsCode := &models.SMSCode{
		Phone:     normalizedPhone,
		Code:      code,
		Region:    req.Region,
		Purpose:   req.Purpose,
		Status:    models.CodeStatusPending,
		ExpiresAt: time.Now().Add(cfg.Config.SMS.Global.CodeExpiry),
	}

	// 7. 发送短信
	sendReq := &sms_providers.SendSMSRequest{
		Phone:      normalizedPhone,
		TemplateID: req.TemplateID,
		Region:     req.Region,
		Purpose:    req.Purpose,
		Params: map[string]string{
			"code": code,
		},
	}
	err = cfg.DB().Transaction(func(tx *gorm.DB) error {
		err := tx.Create(smsCode).Error
		if err != nil {
			return err
		}
		smsID, err := provider.SendSMS(x.Context(), sendReq)
		LogSMS(normalizedPhone, req.Region, provider.GetName(), smsID, err)
		if err != nil || smsID == "" {
			return fmt.Errorf("failed to send sms: %v", err)
		}
		return nil
	})
	if err != nil {
		return nil, err
	}
	return &SendCodeResponse{
		ID:        smsCode.ID,
		Phone:     smsCode.Phone,
		ExpiresAt: smsCode.ExpiresAt,
		Interval:  int(cfg.Config.SMS.Global.SendInterval.Seconds()),
	}, nil
}
