package jmap

import (
	"strings"

	"git.sr.ht/~rjarry/aerc/worker/types"
	"git.sr.ht/~rockorager/go-jmap"
	"git.sr.ht/~rockorager/go-jmap/mail/email"
	"git.sr.ht/~rockorager/go-jmap/mail/mailbox"
)

func (w *JMAPWorker) translateSearch(
	mbox jmap.ID, criteria *types.SearchCriteria,
) email.Filter {
	cond := new(email.FilterCondition)

	if mbox == "" {
		// all mail virtual folder: display all but trash and spam
		var mboxes []jmap.ID
		if id, ok := w.roles[mailbox.RoleJunk]; ok {
			mboxes = append(mboxes, id)
		}
		if id, ok := w.roles[mailbox.RoleTrash]; ok {
			mboxes = append(mboxes, id)
		}
		cond.InMailboxOtherThan = mboxes
	} else {
		cond.InMailbox = mbox
	}
	if criteria == nil {
		return cond
	}

	// dates
	if !criteria.StartDate.IsZero() {
		cond.After = &criteria.StartDate
	}
	if !criteria.EndDate.IsZero() {
		cond.Before = &criteria.EndDate
	}

	// general search terms
	terms := strings.Join(criteria.Terms, " ")
	switch {
	case criteria.SearchAll:
		cond.Text = terms
	case criteria.SearchBody:
		cond.Body = terms
	default:
		cond.Subject = terms
	}

	filter := &email.FilterOperator{Operator: jmap.OperatorAND}
	filter.Conditions = append(filter.Conditions, cond)

	// keywords/flags
	for kw := range flagsToKeywords(criteria.WithFlags) {
		filter.Conditions = append(filter.Conditions,
			&email.FilterCondition{HasKeyword: kw})
	}
	for kw := range flagsToKeywords(criteria.WithoutFlags) {
		filter.Conditions = append(filter.Conditions,
			&email.FilterCondition{NotKeyword: kw})
	}

	// recipients
	addrs := &email.FilterOperator{
		Operator: jmap.OperatorOR,
	}
	for _, from := range criteria.From {
		addrs.Conditions = append(addrs.Conditions,
			&email.FilterCondition{From: from})
	}
	for _, to := range criteria.To {
		addrs.Conditions = append(addrs.Conditions,
			&email.FilterCondition{To: to})
	}
	for _, cc := range criteria.Cc {
		addrs.Conditions = append(addrs.Conditions,
			&email.FilterCondition{Cc: cc})
	}
	if len(addrs.Conditions) > 0 {
		filter.Conditions = append(filter.Conditions, addrs)
	}

	// specific headers
	headers := &email.FilterOperator{
		Operator: jmap.OperatorAND,
	}
	for h, values := range criteria.Headers {
		for _, v := range values {
			headers.Conditions = append(headers.Conditions,
				&email.FilterCondition{Header: []string{h, v}})
		}
	}
	if len(headers.Conditions) > 0 {
		filter.Conditions = append(filter.Conditions, headers)
	}

	return filter
}
