package healthhttp

import (
	"context"
	"encoding/json"
	"net/http"
	"time"

	"gitea.dwysokinski.me/twhelp/corev3/internal/health"
)

type handler struct {
	check func(ctx context.Context) health.Result
}

var _ http.Handler = (*handler)(nil)

func LiveHandler(h *health.Health) http.Handler {
	return &handler{
		check: h.CheckLive,
	}
}

func ReadyHandler(h *health.Health) http.Handler {
	return &handler{
		check: h.CheckReady,
	}
}

type singleCheckResult struct {
	Status        string    `json:"status"`
	FailureReason string    `json:"err,omitempty"`
	Time          time.Time `json:"time"`
}

type response struct {
	Status string                         `json:"status"`
	Checks map[string][]singleCheckResult `json:"checks"`
}

func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	result := h.check(r.Context())

	respChecks := make(map[string][]singleCheckResult, len(result.Checks))
	for name, checks := range result.Checks {
		respChecks[name] = make([]singleCheckResult, 0, len(checks))

		for _, ch := range checks {
			failureReason := ""
			if ch.Err != nil {
				failureReason = ch.Err.Error()
			}

			respChecks[name] = append(respChecks[name], singleCheckResult{
				Status:        ch.Status.String(),
				FailureReason: failureReason,
				Time:          ch.Time,
			})
		}
	}

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(healthStatusToHTTPStatus(result.Status))
	_ = json.NewEncoder(w).Encode(response{
		Status: result.Status.String(),
		Checks: respChecks,
	})
}

func healthStatusToHTTPStatus(status health.Status) int {
	switch status {
	case health.StatusPass:
		return http.StatusOK
	case health.StatusFail:
		return http.StatusServiceUnavailable
	default:
		return http.StatusInternalServerError
	}
}
