package mailimp

import (
	"net/http"
	"os"

	mb "github.com/tech/sendico/notification/internal/server/notificationimp/mail/internal/builder"
	mmail "github.com/tech/sendico/notification/internal/server/notificationimp/mail/messagebuilder"
	"github.com/tech/sendico/pkg/merrors"
	"github.com/tech/sendico/pkg/messaging"
	"github.com/tech/sendico/pkg/mlogger"
	"github.com/sendgrid/sendgrid-go"
	"github.com/sendgrid/sendgrid-go/helpers/mail"
	"go.uber.org/zap"
)

type KeysConfig struct {
	Email string `yaml:"email"`
	Name  string `yaml:"name"`
	URL   string `yaml:"url"`
	ID    string `yaml:"id"`
}

type Sender struct {
	Address string `yaml:"address"`
	Name    string `yaml:"name"`
}

type SGEmailConfig struct {
	Sender Sender `yaml:"sender"`
}

type SendGridConfig struct {
	APIKeyEnv string        `yaml:"api_key_env"`
	Email     SGEmailConfig `yaml:"email"`
	Keys      KeysConfig    `yaml:"keys"`
}

type SendGridNotifier struct {
	logger   mlogger.Logger
	client   *sendgrid.Client
	config   *SendGridConfig
	producer messaging.Producer
}

func (sg *SendGridNotifier) Send(mb mmail.MailBuilder) error {
	m := mail.NewV3Mail()

	e := mail.NewEmail(sg.config.Email.Sender.Name, sg.config.Email.Sender.Address)
	m.SetFrom(e)

	task, err := mb.Build()
	if err != nil {
		sg.logger.Warn("Failed to build message", zap.Error(err))
		return err
	}
	m.SetTemplateID(task.TemplateID())

	p := mail.NewPersonalization()
	for _, recipient := range task.Recipients() {
		p.AddTos(mail.NewEmail(recipient, recipient))
	}

	for k, v := range task.Parameters() {
		p.SetDynamicTemplateData(k, v)
	}

	m.AddPersonalizations(p)

	response, err := sg.client.Send(m)
	if err != nil {
		sg.logger.Warn("Failed to send email", zap.Error(err), zap.Any("task", &task))
		return err
	}
	if (response.StatusCode != http.StatusOK) && (response.StatusCode != http.StatusAccepted) {
		sg.logger.Warn("Unexpected SendGrid sresponse", zap.Int("status_code", response.StatusCode),
			zap.String("sresponse", response.Body), zap.Any("task", &task))
		return merrors.Internal("email_notification_not_sent")
	}

	sg.logger.Info("Email sent successfully", zap.Strings("recipients", task.Recipients()), zap.String("template_id", task.TemplateID()))
	// if err = sg.producer.SendMessage(model.NewNotification(model.NTEmail, model.NAComplete), &task); err != nil {
	// 	sg.logger.Warn("Failed to send email statistics", zap.Error(err), zap.Strings("recipients", task.Recipients), zap.String("template_id", task.TemplateID))
	// }
	return nil
}

func (sg *SendGridNotifier) MailBuilder() mmail.MailBuilder {
	return mb.NewMessageBuilder()
}

func NewSendGridNotifier(logger mlogger.Logger, producer messaging.Producer, config *SendGridConfig) (*SendGridNotifier, error) {
	apiKey := os.Getenv(config.APIKeyEnv)
	if apiKey == "" {
		logger.Warn("No SendGrid API key")
		return nil, merrors.NoData("No SendGrid API key")
	}
	return &SendGridNotifier{
		logger:   logger.Named("sendgrid"),
		client:   sendgrid.NewSendClient(apiKey),
		config:   config,
		producer: producer,
	}, nil
}
