package storage

import (
	"net/mail"
	"regexp"
	"strings"
	"time"

	"github.com/axllent/mailpit/config"
	"github.com/axllent/mailpit/logger"
	"github.com/axllent/mailpit/server/websockets"
	"github.com/jhillyerd/enmime"
	"github.com/k3a/html2text"
	"github.com/ostafen/clover/v2"
)

// Return a header field as a []*mail.Address, or "null" is not found/empty
func addressToSlice(env *enmime.Envelope, key string) []*mail.Address {
	data, _ := env.AddressList(key)

	return data
}

// Generate the search text based on some header fields (to, from, subject etc)
// and either the stripped HTML body (if exists) or text body
func createSearchText(env *enmime.Envelope) string {
	var b strings.Builder

	b.WriteString(env.GetHeader("From") + " ")
	b.WriteString(env.GetHeader("Subject") + " ")
	b.WriteString(env.GetHeader("To") + " ")
	b.WriteString(env.GetHeader("Cc") + " ")
	b.WriteString(env.GetHeader("Bcc") + " ")
	h := strings.TrimSpace(html2text.HTML2Text(env.HTML))
	if h != "" {
		b.WriteString(h + " ")
	} else {
		b.WriteString(env.Text + " ")
	}
	// add attachment filenames
	for _, a := range env.Attachments {
		b.WriteString(a.FileName + " ")
	}

	d := cleanString(b.String())

	return d
}

// cleanString removed unwanted characters from stored search text and search queries
func cleanString(str string) string {
	// remove/replace new lines
	re := regexp.MustCompile(`(\r?\n|\t|>|<|"|:|\,|;)`)
	str = re.ReplaceAllString(str, " ")
	// remove duplicate whitespace and trim
	return strings.ToLower(strings.Join(strings.Fields(strings.TrimSpace(str)), " "))
}

// Auto-prune runs every 5 minutes to automatically delete oldest messages
// if total is greater than the threshold
func pruneCron() {
	for {
		// time.Sleep(5 * 60 * time.Second)
		time.Sleep(60 * time.Second)
		mailboxes, err := db.ListCollections()
		if err != nil {
			logger.Log().Errorf("[db] %s", err)
			continue
		}

		for _, m := range mailboxes {
			total, _ := db.Count(clover.NewQuery(m))
			if total > config.MaxMessages {
				limit := total - config.MaxMessages
				if limit > 5000 {
					limit = 5000
				}
				start := time.Now()
				if err := db.Delete(clover.NewQuery(m).
					Sort(clover.SortOption{Field: "Created", Direction: 1}).
					Limit(limit)); err != nil {
					logger.Log().Warnf("Error pruning %s: %s", m, err.Error())
					continue
				}
				elapsed := time.Since(start)
				logger.Log().Infof("Pruned %d messages from %s in %s", limit, m, elapsed)
				statsRefresh(m)
				if !strings.HasSuffix(m, "_data") {
					websockets.Broadcast("prune", nil)
				}
			}
		}
	}
}