package plugin

import (
	"log/slog"

	"github.com/alexei/tinyforge/internal/crypto"
	"github.com/alexei/tinyforge/internal/notify"
)

// DispatchNotificationForWorkload sends `event` to every notification
// route configured for the workload. Resolution order:
//
//  1. workload_notifications rows matching `event.Type` — multi-route
//     fan-out (e.g. Slack alerts + Discord successes per workload).
//  2. If zero matching rows AND the legacy single-URL columns on the
//     workload row are set, send to that URL — backwards compat for
//     installs that pre-date the new table.
//  3. Otherwise, fall through to settings.notification_url so the global
//     destination still fires for workloads with no per-row config.
//
// Secrets are decrypted via deps.EncKey before sending. A failed decrypt
// degrades to "send unsigned" with a warning rather than dropping the
// notification — the operator still gets the alert, they just need to
// re-save the secret. Fire-and-forget: failures are logged inside
// deps.Notifier and never bubble up here.
//
// Callers (static / dockerfile / image / compose plugins) pass an
// already-populated Event; this helper does not synthesize the payload
// shape, only the routing.
func DispatchNotificationForWorkload(deps Deps, w Workload, event notify.Event) {
	if deps.Notifier == nil {
		return
	}
	rows, err := deps.Store.ListWorkloadNotifications(w.ID)
	if err != nil {
		slog.Warn("notify: list workload routes failed",
			"workload", w.ID, "error", err)
		rows = nil
	}

	matched := 0
	for _, n := range rows {
		if !n.MatchesEventType(event.Type) {
			continue
		}
		matched++
		secret := ""
		if n.Secret != "" {
			dec, derr := crypto.Decrypt(deps.EncKey, n.Secret)
			if derr != nil {
				slog.Warn("notify: decrypt workload secret failed — sending unsigned",
					"workload", w.ID, "route", n.Name, "error", derr)
			} else {
				secret = dec
			}
		}
		deps.Notifier.SendSigned(n.URL, secret, notify.TierSite, event)
	}
	if matched > 0 {
		return
	}

	// Legacy fallback: single per-workload destination on workloads.notification_url.
	if w.NotificationURL != "" {
		deps.Notifier.SendSigned(w.NotificationURL, w.NotificationSecret, notify.TierSite, event)
		return
	}

	// Global fallback so a one-line config in settings still notifies
	// every workload without a per-row override.
	settings, err := deps.Store.GetSettings()
	if err != nil {
		slog.Warn("notify: settings lookup for global fallback failed",
			"workload", w.ID, "error", err)
		return
	}
	if settings.NotificationURL == "" {
		return
	}
	deps.Notifier.SendSigned(settings.NotificationURL, settings.NotificationSecret, notify.TierSettings, event)
}
