package api

// Outgoing-webhook signing-secret + send-test endpoints. After the hard
// cutover only the settings tier survives at the API surface; per-workload
// notification settings live on the workload row itself and are accessed
// via the workload endpoints.

import (
	"context"
	"log/slog"
	"net/http"
	"time"

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

// notificationSecretResponse is what the GET / regenerate endpoints return.
// The secret is revealed in cleartext exactly once per request — UI is
// expected to copy or hash it for display, not store it long-term.
type notificationSecretResponse struct {
	Secret    string `json:"secret"`
	HasSecret bool   `json:"has_secret"`
}

// testEventTimeout caps how long we wait for the receiver before declaring
// the test failed. Mirrors the production notifier's per-request timeout
// (10s) so test results are predictive of real send behaviour.
const testEventTimeout = 10 * time.Second

// buildTestEvent constructs the synthetic payload used by every "send
// test" endpoint. Marking it as type "test" prevents a misconfigured
// receiver from mistaking a wiring check for a real deploy event.
func buildTestEvent(project, stage string) notify.Event {
	return notify.Event{
		Type:    "test",
		Project: project,
		Stage:   stage,
	}
}

// ---------------------------------------------------------------------------
// Global / settings tier
// ---------------------------------------------------------------------------

// getSettingsNotificationSecret handles GET /api/settings/notification-secret.
// Lazily generates a secret if one was never set (typical for sites
// upgrading from a pre-signing build).
func (s *Server) getSettingsNotificationSecret(w http.ResponseWriter, r *http.Request) {
	secret, err := s.store.EnsureSettingsNotificationSecret()
	if err != nil {
		slog.Error("get settings notification secret", "error", err)
		respondError(w, http.StatusInternalServerError, "failed to load secret")
		return
	}
	respondJSON(w, http.StatusOK, notificationSecretResponse{Secret: secret, HasSecret: secret != ""})
}

// regenerateSettingsNotificationSecret handles POST
// /api/settings/notification-secret/regenerate. Replaces the existing
// secret with a fresh one, invalidating signatures verified against the
// old secret.
func (s *Server) regenerateSettingsNotificationSecret(w http.ResponseWriter, r *http.Request) {
	secret := generateWebhookSecret()
	if err := s.store.SetSettingsNotificationSecret(secret); err != nil {
		slog.Error("regenerate settings notification secret", "error", err)
		respondError(w, http.StatusInternalServerError, "failed to rotate secret")
		return
	}
	slog.Info("settings notification secret rotated")
	respondJSON(w, http.StatusOK, notificationSecretResponse{Secret: secret, HasSecret: true})
}

// disableSettingsNotificationSigning handles POST
// /api/settings/notification-secret/disable. Clears the secret so further
// outgoing notifications are unsigned. Useful for receivers that don't
// support HMAC verification.
func (s *Server) disableSettingsNotificationSigning(w http.ResponseWriter, r *http.Request) {
	if err := s.store.SetSettingsNotificationSecret(""); err != nil {
		slog.Error("disable settings notification signing", "error", err)
		respondError(w, http.StatusInternalServerError, "failed to disable signing")
		return
	}
	respondJSON(w, http.StatusOK, notificationSecretResponse{Secret: "", HasSecret: false})
}

// settingsNotificationTest handles POST /api/settings/notification-test.
// Sends a synthetic test event to the global webhook URL using the global
// secret.
func (s *Server) settingsNotificationTest(w http.ResponseWriter, r *http.Request) {
	settings, err := s.store.GetSettings()
	if err != nil {
		respondError(w, http.StatusInternalServerError, "failed to load settings")
		return
	}
	if settings.NotificationURL == "" {
		respondError(w, http.StatusBadRequest, "no global notification URL configured")
		return
	}
	ctx, cancel := context.WithTimeout(r.Context(), testEventTimeout)
	defer cancel()
	result := s.notifier.SendSyncForTest(
		ctx, settings.NotificationURL, settings.NotificationSecret, notify.TierSettings,
		buildTestEvent("__tinyforge__", ""),
	)
	respondJSON(w, http.StatusOK, result)
}
