package mailhandler

import (
	"fmt"
	"time"

	"github.com/pingcap/log"

	"github.com/pingcap/dbaas/billing2/billing_errors"
	"github.com/pingcap/dbaas/billing2/config"
	"github.com/sendgrid/sendgrid-go"
	"github.com/sendgrid/sendgrid-go/helpers/mail"
	"go.uber.org/zap"
)

var (
	SendNeedConfirmInvoiceNotifyTemplateID = "d-b26968996eb94417afe19c8c2ea6abab"
	SendNotificationOnUserOperateContract  = "d-c74ff0a1348f4f928166f15ab81d1461"
	SendNotificationOnSubmitContract       = "d-a635742967f74f50aa796c2c26ef2683"
	mailEnvSuffixKey                       = "env_suffix"
)

type MailHandler interface {
	SendMail(reciever []string, templateID string, vars map[string]string) error
}

var global MailHandler = &MailHandlerImpl{}

func GetHandler() MailHandler {
	return global
}

func SetHandler(handler MailHandler) {
	global = handler
}

type MailHandlerImpl struct {
}

type sendMailOpts struct {
	Track        bool
	DeliveryTime time.Time
	FromAddr     string
	CC           []string
}

func newDefaultSendMailOpts() *sendMailOpts {
	return &sendMailOpts{
		Track:        true,
		DeliveryTime: time.Now(),
		FromAddr:     config.Get().GetString(config.DefaultMailFrom),
	}
}

func (*MailHandlerImpl) SendMail(to []string, templateID string, vars map[string]string) error {
	if !config.Get().GetBool(config.EnableMailNotify) {
		log.Info("skip send email by config disabled")
	}

	logger := log.With(zap.String("mailProvider", "sendgrid"))
	opts := newDefaultSendMailOpts()
	logger.Sugar().Infof("try to send email, templateID=%s,to=%s,vars=%+v", templateID, to, vars)
	clearedTos := make([]string, 0, len(to))
	for _, each := range to {
		if each != "" {
			clearedTos = append(clearedTos, each)
		}
	}
	if len(clearedTos) == 0 {
		return nil
	}
	to = clearedTos

	from := mail.NewEmail("", opts.FromAddr)
	toEmails := make([]*mail.Email, 0, len(to))
	ccEmails := make([]*mail.Email, 0, len(opts.CC))
	for _, each := range to {
		toEmails = append(toEmails, mail.NewEmail("", each))
	}
	for _, each := range opts.CC {
		ccEmails = append(ccEmails, mail.NewEmail("", each))
	}
	personalize := mail.NewPersonalization()
	personalize.AddTos(toEmails...)
	personalize.AddCCs(ccEmails...)
	for k, v := range vars {
		personalize.SetDynamicTemplateData(k, v)
	}

	personalize.SetDynamicTemplateData(mailEnvSuffixKey, config.Get().GetString(config.MailEnvSuffix))
	message := mail.NewV3Mail()
	message.SetFrom(from)
	message.AddPersonalizations(personalize)
	message.SetTrackingSettings(mail.NewTrackingSettings().SetOpenTracking(mail.NewOpenTrackingSetting().SetEnable(opts.Track)))
	message.SetSendAt(int(opts.DeliveryTime.Unix()))
	message.SetTemplateID(templateID)

	logger.Sugar().Infof("try to send email, templateID=%s,len(to)=%d,len(cc)=%d", templateID, len(to), len(opts.CC))
	sgCli := sendgrid.NewSendClient(config.Get().GetString(config.MailApiKey))

	resp, err := sgCli.Send(message)
	if err != nil {
		logger.Sugar().Warnf("send mail by sendgrid failed: %s", err)
		return billing_errors.NewSystemError(err)
	}
	logger.Sugar().Infof("email sent. statusCode=%d,body=%s", resp.StatusCode, resp.Body)
	if resp.StatusCode >= 400 {
		return billing_errors.NewSystemError(fmt.Errorf("send mail failed, statusCode=%d", resp.StatusCode))
	}
	return nil

}
