package mynalogsync

import (
	"context"
	"time"

	"go.uber.org/zap"

	"scrabble/backend/internal/account"
)

// Run drives the automatic export until the context ends.
//
// A tick with nothing to do costs one local query: the queue is read before anything authenticates,
// so an installation with no unfiled income never appears at the tax service at all. The automatic
// mode is armed from the admin console rather than from configuration, so that it can be switched
// on only once the operator has watched a run go through by hand.
func (e *Exporter) Run(ctx context.Context, interval time.Duration) {
	ticker := time.NewTicker(interval)
	defer ticker.Stop()
	for {
		select {
		case <-ctx.Done():
			return
		case <-ticker.C:
			e.tick(ctx)
		}
	}
}

// tick performs one automatic run, if the rail is signed in, armed and not paused.
func (e *Exporter) tick(ctx context.Context) {
	stored, ok, err := e.payments.MyNalogSession(ctx)
	if err != nil {
		e.log.Error("mynalog session could not be read", zap.Error(err))
		return
	}
	if !ok || !stored.AutoEnabled || stored.Paused() {
		return
	}
	sum, err := e.RunBatch(ctx, WorkerBudget)
	if err != nil {
		e.log.Error("mynalog automatic export failed", zap.Error(err))
		return
	}
	if sum.Registered == 0 && sum.Cancelled == 0 && sum.NotRequired == 0 &&
		sum.Failed == 0 && sum.Unknown == 0 {
		return // nothing happened; not worth a log line every quarter of an hour
	}
	e.log.Info("mynalog automatic export ran",
		zap.Int("registered", sum.Registered), zap.Int("cancelled", sum.Cancelled),
		zap.Int("not_required", sum.NotRequired), zap.Int("failed", sum.Failed),
		zap.Int("unknown", sum.Unknown), zap.String("stopped", sum.Stopped))
}

// MailAlerter delivers operator alerts by email, reusing the relay the admin digest already uses.
type MailAlerter struct {
	mail account.Mailer
	from string
	to   string
}

// NewMailAlerter builds the alert channel. It returns nil unless a distinct admin sender and
// recipient are configured, matching how the existing admin digest stays inert without them.
func NewMailAlerter(mail account.Mailer, from, to string) *MailAlerter {
	if mail == nil || from == "" || to == "" {
		return nil
	}
	return &MailAlerter{mail: mail, from: from, to: to}
}

// Alert sends one operator alert. kind is the caller's deduplication key and is deliberately not
// put in the message.
//
// The body never carries a link into the admin console: an admin URL must not travel by email,
// where a provider could cache or index it (the same rule the admin digest follows).
func (a *MailAlerter) Alert(ctx context.Context, _, subject, body string) error {
	return a.mail.Send(ctx, account.Message{
		From:    a.from,
		To:      a.to,
		Subject: subject,
		Text:    body,
	})
}
