// M13a W5: admin HTTP routes for routerd. Two routes are
// registered when BA_AUTHD_JWT_SECRET is set:
//
//	GET  /v1/admin/dedupe/state — number of pending collapse
//	  windows. Read-only. Any authenticated user.
//	POST /v1/admin/dedupe/flush — force-flush every pending
//	  collapse immediately (calls Collapser.FlushAll). Destructive:
//	  re-publishes all held alerts to NATS. super_admin or
//	  tenant_admin only.
//
// When BA_AUTHD_JWT_SECRET is unset, no admin routes are
// registered and the existing /health + /metrics keep working
// unchanged (LAN deploy path).
package main

import (
	"encoding/json"
	"log/slog"
	"net/http"

	"git3.techno-world.net/lrosales/broad-announce/internal/authd"
	"git3.techno-world.net/lrosales/broad-announce/internal/dedupe"
)

// wireAdminRoutes wires the admin routes onto mux. When the JWT
// gate is disabled (env not set), the function logs a warning and
// returns without registering anything — backward compat for
// non-M13 deploys.
func wireAdminRoutes(
	mux *http.ServeMux,
	collapser *dedupe.Collapser,
	state *fanoutState,
	logger *slog.Logger,
) {
	if !authd.EnvEnabled() {
		logger.Warn("admin routes are DISABLED (set BA_AUTHD_JWT_SECRET to enable)")
		return
	}
	ad, err := authd.NewFromEnv()
	if err != nil {
		logger.Error("BA_AUTHD_JWT_SECRET set but authd init failed; admin routes DISABLED", "err", err)
		return
	}
	logger.Info("admin routes enabled with JWT gate")

	mux.Handle("GET /v1/admin/dedupe/state",
		ad.RequireAuth(http.HandlerFunc(handleDedupeState(collapser, state, logger))))
	mux.Handle("POST /v1/admin/dedupe/flush",
		ad.RequireRole("super_admin", "tenant_admin")(
			http.HandlerFunc(handleDedupeFlush(collapser, state, logger))))
}

// handleDedupeState returns the count of pending collapse windows.
// `collapser.Pending()` is the source of truth (it owns the
// per-(source,key) map); `state.len()` mirrors it but tracks
// the cached targets, so we report both for visibility.
func handleDedupeState(collapser *dedupe.Collapser, state *fanoutState, logger *slog.Logger) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		pending := collapser.Pending()
		cached := state.len()
		w.Header().Set("Content-Type", "application/json")
		_ = json.NewEncoder(w).Encode(map[string]any{
			"pending_collapses":    pending,
			"cached_target_lists":  cached,
		})
	}
}

// handleDedupeFlush force-flushes every pending collapse. The
// Collapser's Run loop also reads its own pending map and fires
// onFlush, so this is just a no-wait path to the same outcome.
// Safe to call when the map is empty (no-op).
func handleDedupeFlush(collapser *dedupe.Collapser, state *fanoutState, logger *slog.Logger) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		before := collapser.Pending()
		collapser.FlushAll()
		actor := ""
		if c := authd.ClaimsFromContext(r.Context()); c != nil {
			actor = c.UserID
		}
		logger.Info("admin dedupe flush",
			"pending_before", before,
			"actor", actor,
		)
		w.Header().Set("Content-Type", "application/json")
		_ = json.NewEncoder(w).Encode(map[string]any{
			"flushed":        true,
			"pending_before": before,
		})
	}
}
