package pager

import (
	"fmt"
	"strings"

	twilio "github.com/twilio/twilio-go"
	twilioApi "github.com/twilio/twilio-go/rest/api/v2010"
)

const twilioVoiceMessage = "This is an urgent Lark notification. Please check your Lark messages as soon as possible."

type TwilioCallerNumber struct {
	Prefix string
	Number string
}

type TwilioCallerConfig struct {
	AccountSID string
	AuthToken  string
	Callers    []TwilioCallerNumber
}

type twilioCaller struct {
	raw     *twilio.RestClient
	callers []TwilioCallerNumber
}

func NewTwilioCaller(conf TwilioCallerConfig) (Caller, error) {
	if conf.AccountSID == "" || conf.AuthToken == "" {
		return nil, fmt.Errorf("twilio caller: missing account_sid or auth_token")
	}
	client := twilio.NewRestClientWithParams(twilio.ClientParams{
		Username: conf.AccountSID,
		Password: conf.AuthToken,
	})
	return &twilioCaller{
		raw:     client,
		callers: conf.Callers,
	}, nil
}

func (c *twilioCaller) Call(number string) error {
	from, err := c.selectCallerNumber(number)
	if err != nil {
		return err
	}

	params := &twilioApi.CreateCallParams{}
	params.SetTo(number)
	params.SetFrom(from)
	params.SetTwiml(fmt.Sprintf(
		"<Response><Say language=\"en-US\">%s</Say></Response>",
		twilioVoiceMessage,
	))

	_, err = c.raw.Api.CreateCall(params)
	if err != nil {
		return fmt.Errorf("twilio caller: create call failed: %w", err)
	}
	return nil
}

func (c *twilioCaller) selectCallerNumber(callNumber string) (string, error) {
	var (
		fallback    string
		bestMatch   string
		bestMatchLn int
	)
	for _, caller := range c.callers {
		if caller.Prefix == "+1" {
			fallback = caller.Number
		}
		if strings.HasPrefix(callNumber, caller.Prefix) && len(caller.Prefix) > bestMatchLn {
			bestMatch = caller.Number
			bestMatchLn = len(caller.Prefix)
		}
	}
	if bestMatch != "" {
		return bestMatch, nil
	}
	if fallback != "" {
		return fallback, nil
	}
	return "", fmt.Errorf("twilio caller: no caller configured for number prefix: %s", callNumber)
}
