package dispatcher

import (
	"bytes"
	"errors"
	"fmt"
	"net/mail"
	"strings"
)

const MaxEnvelopeBytes = 64 * 1024

// Envelope is the only application payload accepted by the dispatcher. Message
// must already be a complete YAMN transport envelope, not user supplied mail.
type Envelope struct {
	EntryAddress string `json:"entry_address"`
	Message      []byte `json:"message"`
}

func (e Envelope) Validate(allowedDomains map[string]struct{}) error {
	if len(e.Message) == 0 || len(e.Message) > MaxEnvelopeBytes {
		return fmt.Errorf("invalid YAMN envelope size")
	}
	if bytes.Contains(e.Message, []byte("\r")) {
		return errors.New("YAMN envelope must use LF line endings")
	}
	address, err := mail.ParseAddress(e.EntryAddress)
	if err != nil || address.Address != e.EntryAddress {
		return errors.New("invalid entry remailer address")
	}
	parts := strings.Split(address.Address, "@")
	if len(parts) != 2 || parts[0] == "" || parts[1] == "" {
		return errors.New("invalid entry remailer address")
	}
	if _, ok := allowedDomains[strings.ToLower(parts[1])]; !ok {
		return errors.New("entry remailer domain is not allowed")
	}
	if !bytes.HasPrefix(e.Message, []byte("To: "+e.EntryAddress+"\n")) {
		return errors.New("YAMN envelope recipient does not match entry remailer")
	}
	if !bytes.Contains(e.Message, []byte("-----BEGIN REMAILER MESSAGE-----\n")) {
		return errors.New("invalid YAMN envelope")
	}
	return nil
}
