package pager

import (
	"fmt"
	"math/rand/v2"

	openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
	dyvmsapi20170525 "github.com/alibabacloud-go/dyvmsapi-20170525/v4/client"
	util "github.com/alibabacloud-go/tea-utils/v2/service"
	"github.com/alibabacloud-go/tea/tea"
)

type AliCallerConfig struct {
	AccessKeyID     string
	AccessKeySecret string
	TtsCode         string
	CalloutNumbers  []string
	PerMinuteBurst  int
}

type aliCaller struct {
	rl             *generalLimiter
	dyvmCli        *dyvmsapi20170525.Client
	ttsCode        string
	calloutNumbers []string
}

func NewAliCaller(conf AliCallerConfig) (Caller, error) {
	if len(conf.CalloutNumbers) == 0 {
		return nil, fmt.Errorf("ali caller: no callout numbers configured")
	}
	cfg := &openapi.Config{
		AccessKeyId:     tea.String(conf.AccessKeyID),
		AccessKeySecret: tea.String(conf.AccessKeySecret),
	}
	cfg.Endpoint = tea.String("dyvmsapi.aliyuncs.com")
	dyvmsCli, err := dyvmsapi20170525.NewClient(cfg)
	if err != nil {
		return nil, fmt.Errorf("ali caller: init dyvmsapi client: %w", err)
	}
	burst := conf.PerMinuteBurst
	if burst <= 0 {
		burst = 20
	}
	return &aliCaller{
		rl:             newGeneralLimiter(burst),
		ttsCode:        conf.TtsCode,
		calloutNumbers: conf.CalloutNumbers,
		dyvmCli:        dyvmsCli,
	}, nil
}

func (c *aliCaller) Call(number string) error {
	if !c.rl.Allow() {
		return fmt.Errorf("ali caller: rate limit reached for %s", number)
	}

	var calloutNumber string
	if len(c.calloutNumbers) == 1 {
		calloutNumber = c.calloutNumbers[0]
	} else {
		calloutNumber = c.calloutNumbers[rand.IntN(len(c.calloutNumbers))]
	}

	req := &dyvmsapi20170525.SingleCallByTtsRequest{
		CalledShowNumber: tea.String(calloutNumber),
		CalledNumber:     tea.String(number),
		TtsCode:          tea.String(c.ttsCode),
	}
	runtime := &util.RuntimeOptions{}

	tryErr := func() (_e error) {
		defer func() {
			if r := tea.Recover(recover()); r != nil {
				_e = r
			}
		}()
		_, _e = c.dyvmCli.SingleCallByTtsWithOptions(req, runtime)
		return _e
	}()

	if tryErr != nil {
		return fmt.Errorf("ali caller: voice api failed for %s: %w", number, tryErr)
	}
	return nil
}
