package health

import (
	"encoding/json"
	"net/http"
	"sync/atomic"
	"time"
)

// Status represents agent health for liveness and readiness probes.
type Status struct {
	Status    string    `json:"status"`
	Agent     string    `json:"agent"`
	Version   string    `json:"version"`
	Uptime    string    `json:"uptime"`
	Timestamp time.Time `json:"timestamp"`
}

// Server exposes HTTP health endpoints for the node agent.
type Server struct {
	addr      string
	version   string
	startedAt time.Time
	ready     atomic.Bool
	mux       *http.ServeMux
}

// NewServer creates a health HTTP server bound to addr.
func NewServer(addr, version string) *Server {
	s := &Server{
		addr:      addr,
		version:   version,
		startedAt: time.Now().UTC(),
		mux:       http.NewServeMux(),
	}
	s.mux.HandleFunc("GET /healthz", s.handleLiveness)
	s.mux.HandleFunc("GET /readyz", s.handleReadiness)
	return s
}

// SetReady toggles readiness for orchestration probes.
func (s *Server) SetReady(ready bool) {
	s.ready.Store(ready)
}

// Handler returns the HTTP handler for embedding in tests.
func (s *Server) Handler() http.Handler {
	return s.mux
}

// ListenAndServe starts the health server.
func (s *Server) ListenAndServe() error {
	return http.ListenAndServe(s.addr, s.mux)
}

func (s *Server) handleLiveness(w http.ResponseWriter, _ *http.Request) {
	s.writeStatus(w, http.StatusOK, "alive")
}

func (s *Server) handleReadiness(w http.ResponseWriter, _ *http.Request) {
	if !s.ready.Load() {
		s.writeStatus(w, http.StatusServiceUnavailable, "not_ready")
		return
	}
	s.writeStatus(w, http.StatusOK, "ready")
}

func (s *Server) writeStatus(w http.ResponseWriter, code int, status string) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(code)
	_ = json.NewEncoder(w).Encode(Status{
		Status:    status,
		Agent:     "node-agent",
		Version:   s.version,
		Uptime:    time.Since(s.startedAt).Round(time.Second).String(),
		Timestamp: time.Now().UTC(),
	})
}
