package mailv2

import (
	"context"
	"encoding/base64"
	"fmt"

	"github.com/sendgrid/sendgrid-go"
	"github.com/sendgrid/sendgrid-go/helpers/mail"
	"github.com/tidbcloud/pkgv2/log"
	"go.uber.org/zap"
)

var (
	_ Facade = &sendgridProvider{}
)

type sendgridProvider struct {
	cli *sendgrid.Client
}

func mustGetTemplateId(name string) string {
	id, ok := sgTemplateName2id[name]
	if !ok {
		panic(fmt.Sprintf("can't find template: %s", name))
	}
	return id
}

func NewSendgrid(cli *sendgrid.Client) *sendgridProvider {
	return &sendgridProvider{
		cli: cli,
	}
}
func (s *sendgridProvider) SendMailWithTemplate(ctx context.Context, to []string, subject, templateName string, vars map[string]string, opts *SendMailOpts) error {
	logger := log.WithContextL(ctx).With(zap.String("mailProvider", "sendgrid"))
	logger.Sugar().Infof("try to send email, templateName=%s,to=%s,vars=%+v", templateName, to, vars)
	templateID := mustGetTemplateId(templateName)

	return s.SendMailWithTemplateID(ctx, to, subject, templateID, vars, opts)
}

func (s *sendgridProvider) SendMailWithTemplateID(ctx context.Context, to []string, subject, templateID string, vars map[string]string, opts *SendMailOpts) error {
	logger := log.WithContextL(ctx).With(zap.String("mailProvider", "sendgrid"))
	if opts == nil {
		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)
	}
	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)

	for _, each := range opts.Attachments {
		encodedContent := base64.StdEncoding.EncodeToString(each.Data)
		attach := mail.NewAttachment().SetFilename(each.Filename).SetContent(encodedContent).
			SetDisposition("attachment").SetType(each.MimeType)
		message.AddAttachment(attach)
	}

	logger.Sugar().Infof("try to send email, templateID=%s,len(to)=%d,len(cc)=%d", templateID, len(to), len(opts.CC))
	resp, err := s.cli.Send(message)
	if err != nil {
		logger.Sugar().Warnf("send mail by sendgrid failed: %s", err)
		return err
	}
	logger.Sugar().Infof("email sent. statusCode=%d,body=%s", resp.StatusCode, resp.Body)
	if resp.StatusCode >= 400 {
		return fmt.Errorf("send mail failed, statusCode=%d", resp.StatusCode)
	}
	return nil
}
