package httpx

import (
	"context"
	"errors"
	"net/http"
)

// Late-bound providers: these are wired by later subsystems (atomizer
// client, work-performer client, sync manager, job runner) after the server
// is constructed. All accessors are nil-safe so the admin status panel
// degrades gracefully while subsystems are absent (e.g. in tests).

// BreakerInfo exposes a circuit breaker's state for the status panel.
type BreakerInfo interface {
	BreakerState() string // closed | open | half-open
}

// StatusProvider returns arbitrary JSON-marshalable status payloads.
type StatusProvider interface {
	Statuses() any
}

func (s *Server) SetAtomizerInfo(b BreakerInfo)  { s.atomizer = b }
func (s *Server) SetPerformerInfo(b BreakerInfo) { s.performer = b }

// SetSyncTrigger wires the sync manager's "sync now" entry point.
func (s *Server) SetSyncTrigger(f func(customerID string)) { s.syncTrigger = f }

// Publish forwards a live event to connected clients. Until the WebSocket
// hub lands this is a metrics-only no-op, so subsystems can emit events
// unconditionally.
func (s *Server) Publish(channel, event string, payload any) {
	s.metrics.Inc("events_published_total", 1)
	if s.publishFn != nil {
		s.publishFn(channel, event, payload)
	}
}

// SetPublishFn wires the actual hub broadcast.
func (s *Server) SetPublishFn(f func(channel, event string, payload any)) { s.publishFn = f }

// SetEnqueue wires the background job queue.
func (s *Server) SetEnqueue(f func(ctx context.Context, kind string, payload any) (string, error)) {
	s.enqueueFn = f
}

func (s *Server) enqueue(ctx context.Context, kind string, payload any) (string, error) {
	if s.enqueueFn == nil {
		return "", errors.New("job queue is not running")
	}
	return s.enqueueFn(ctx, kind, payload)
}

// SetWSHandler wires the WebSocket hub's connection handler.
func (s *Server) SetWSHandler(f func(w http.ResponseWriter, r *http.Request, userID string)) {
	s.wsHandler = f
}

// handleWS authenticates the session and hands the connection to the hub.
func (s *Server) handleWS(w http.ResponseWriter, r *http.Request) {
	u := s.pageUser(r)
	if u == nil {
		writeError(w, http.StatusUnauthorized, "unauthenticated", "session required")
		return
	}
	if s.wsHandler == nil {
		writeError(w, http.StatusServiceUnavailable, "ws_unavailable", "live updates are not running")
		return
	}
	s.wsHandler(w, r, u.ID)
}
func (s *Server) SetSyncStatusProvider(p StatusProvider) {
	s.syncProvider = p
}
func (s *Server) SetJobsStatusProvider(p StatusProvider) {
	s.jobsProvider = p
}

func (s *Server) syncStatuses() any {
	if s.syncProvider == nil {
		return []any{}
	}
	return s.syncProvider.Statuses()
}

func (s *Server) jobStatuses() any {
	if s.jobsProvider == nil {
		return map[string]any{}
	}
	return s.jobsProvider.Statuses()
}

// effectiveAtomizerBaseURL honors the admin settings override (§3) over the
// env default.
func (s *Server) effectiveAtomizerBaseURL(ctx context.Context) string {
	if s.store != nil {
		if st, err := s.store.GetSettings(ctx); err == nil && st.AtomizerBaseURLOverride != "" {
			return st.AtomizerBaseURLOverride
		}
	}
	return s.cfg.AtomizerBaseURL
}
