package command

import (
	"context"
	"time"

	"github.com/pkg/errors"

	"forge.cadoles.com/wpetit/fake-smtp/internal/model"
	"forge.cadoles.com/wpetit/fake-smtp/internal/storm"
	"github.com/jhillyerd/enmime"
	"gitlab.com/wpetit/goweb/cqrs"
	"gitlab.com/wpetit/goweb/middleware/container"
)

type StoreEmailRequest struct {
	Envelope *enmime.Envelope
}

func HandleStoreEmail(ctx context.Context, cmd cqrs.Command) error {
	req, ok := cmd.Request().(*StoreEmailRequest)
	if !ok {
		return cqrs.ErrUnexpectedRequest
	}

	ctn, err := container.From(ctx)
	if err != nil {
		return errors.Wrap(err, "could not retrieve service container")
	}

	db, err := storm.From(ctn)
	if err != nil {
		return errors.Wrap(err, "could not retrieve storm service")
	}

	email := &model.Email{
		Headers: make(map[string][]string),
		SentAt:  time.Now(),
	}

	email.HTML = req.Envelope.HTML
	email.Text = req.Envelope.Text

	for _, k := range req.Envelope.GetHeaderKeys() {
		switch k {
		case "From":
			from, err := req.Envelope.AddressList(k)
			if err != nil {
				return errors.Wrapf(err, "could not retrieve '%s' adresses", k)
			}

			email.From = from

		case "To":
			to, err := req.Envelope.AddressList(k)
			if err != nil {
				return errors.Wrapf(err, "could not retrieve '%s' adresses", k)
			}

			email.To = to

		case "Cc":
			cc, err := req.Envelope.AddressList(k)
			if err != nil {
				return errors.Wrapf(err, "could not retrieve '%s' adresses", k)
			}

			email.Cc = cc

		case "Cci":
			cci, err := req.Envelope.AddressList(k)
			if err != nil {
				return errors.Wrapf(err, "could not retrieve '%s' adresses", k)
			}

			email.Cci = cci

		case "Subject":
			email.Subject = req.Envelope.GetHeader(k)

		default:
			email.Headers[k] = req.Envelope.GetHeaderValues(k)
		}
	}

	email.Attachments = make([]*model.Attachment, 0, len(req.Envelope.Attachments))
	for _, a := range req.Envelope.Attachments {
		email.Attachments = append(email.Attachments, &model.Attachment{
			ContentType: a.ContentType,
			Name:        a.FileName,
			Data:        a.Content,
		})
	}

	if err := db.Save(email); err != nil {
		return errors.Wrap(err, "could not save email")
	}

	return nil
}