package alert

import (
	"fmt"
	"primesys_email/src/logger"
	"primesys_email/src/mail"
	"primesys_email/src/utils"
	"strings"
	"sync"
	"time"
)

// at most this many error lines in one alert mail, the full list is in the log file
const maxLinesInMail = 200

// Notifier collects the ERROR lines of a cron run and mails them in one summary
type Notifier struct {
	sender   *mail.DynamicMailSender
	from     string
	password string
	to       string

	mu     sync.Mutex
	errors []string
}

// New returns nil when the alert mail is not configured, all methods work on nil
func New(host string, from string, password string, to string) *Notifier {
	if from == "" || password == "" || to == "" {
		logger.Warn("Error alert mail not configured, set ALERT_FROM_EMAIL, ALERT_FROM_PASSWORD and ALERT_TO_EMAIL")
		return nil
	}

	n := &Notifier{
		sender:   &mail.DynamicMailSender{Host: host},
		from:     from,
		password: password,
		to:       to,
	}
	logger.SetErrorHook(n.record)
	return n
}

func (n *Notifier) record(line string) {
	n.mu.Lock()
	defer n.mu.Unlock()
	n.errors = append(n.errors, line)
}

// Flush mails the errors collected since the last flush, nothing when there were none
func (n *Notifier) Flush(job string) {
	if n == nil {
		return
	}

	n.mu.Lock()
	errors := n.errors
	n.errors = nil
	n.mu.Unlock()

	if len(errors) == 0 {
		return
	}

	now := time.Now().In(utils.ISTLocation()).Format("02/01/2006 15:04")
	subject := fmt.Sprintf("[Primesys Email] %d errors in %s %s", len(errors), job, now)

	lines := errors
	if len(lines) > maxLinesInMail {
		lines = lines[:maxLinesInMail]
	}

	body := fmt.Sprintf("%s finished at %s with %d errors.\n\n%s\n", job, now, len(errors), strings.Join(lines, "\n"))
	if len(errors) > maxLinesInMail {
		body += fmt.Sprintf("\n... %d more, see report_email.log\n", len(errors)-maxLinesInMail)
	}

	// Warn, not Error, so a failing alert mail does not create a new alert
	if err := n.sender.SendMail(n.from, n.password, n.to, subject, body); err != nil {
		logger.Warn("Error alert mail failed to %s : %v", n.to, err)
		return
	}

	logger.Info("Error alert mail sent to %s : %d errors", n.to, len(errors))
}
