package message

import (
	"fmt"
	"io"
	"log/slog"
	"net/textproto"

	"github.com/mjl-/mox/dns"
	"github.com/mjl-/mox/mlog"
	"github.com/mjl-/mox/smtp"
)

// From extracts the address in the From-header.
//
// An RFC5322 message must have a From header.
// In theory, multiple addresses may be present. In practice zero or multiple
// From headers may be present. From returns an error if there is not exactly
// one address. This address can be used for evaluating a DMARC policy against
// SPF and DKIM results.
func From(elog *slog.Logger, strict bool, r io.ReaderAt, p *Part) (raddr smtp.Address, envelope *Envelope, header textproto.MIMEHeader, rerr error) {
	log := mlog.New("message", elog)

	// ../rfc/7489:1243

	// todo: only allow utf8 if enabled in session/message?

	var err error
	if p == nil {
		var pp Part
		pp, err = Parse(log.Logger, strict, r)
		if err != nil {
			// todo: should we continue with p, perhaps headers can be parsed?
			return raddr, nil, nil, fmt.Errorf("parsing message: %v", err)
		}
		p = &pp
	}
	header, err = p.Header()
	if err != nil {
		return raddr, nil, nil, fmt.Errorf("parsing message header: %v", err)
	}
	from := p.Envelope.From
	if len(from) != 1 {
		return raddr, nil, nil, fmt.Errorf("from header has %d addresses, need exactly 1 address", len(from))
	}
	d, err := dns.ParseDomain(from[0].Host)
	if err != nil {
		return raddr, nil, nil, fmt.Errorf("bad domain in from address: %v", err)
	}
	lp, err := smtp.ParseLocalpart(from[0].User)
	if err != nil {
		return raddr, nil, nil, fmt.Errorf("parsing localpart in from address: %v", err)
	}
	addr := smtp.NewAddress(lp, d)
	return addr, p.Envelope, textproto.MIMEHeader(header), nil
}