package httpresponse

import (
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"
)

func getBody(w *httptest.ResponseRecorder) map[string]any {
	var m map[string]any
	if err := json.Unmarshal(w.Body.Bytes(), &m); err != nil {
		return nil
	}
	return m
}

func TestOKEnvelope(t *testing.T) {
	rec := httptest.NewRecorder()
	OK(rec, http.StatusOK, "req-1", map[string]any{"id": 1})
	body := getBody(rec)
	if body["data"] == nil {
		t.Fatal("data missing")
	}
	meta := body["meta"].(map[string]any)
	if meta["request_id"] != "req-1" {
		t.Errorf("request_id = %v, want req-1", meta["request_id"])
	}
	if _, ok := meta["pagination"]; ok {
		t.Error("pagination should be absent for single resources")
	}
}

func TestOKPaginated(t *testing.T) {
	rec := httptest.NewRecorder()
	OKPaginated(rec, http.StatusOK, "r", []int{1, 2}, 1, 20, 45)
	body := getBody(rec)
	p := body["meta"].(map[string]any)["pagination"].(map[string]any)
	if p["total"] != float64(45) || p["last_page"] != float64(3) || p["current_page"] != float64(1) {
		t.Errorf("pagination wrong: %v", p)
	}
}

func TestErrorEnvelope(t *testing.T) {
	rec := httptest.NewRecorder()
	Error(rec, http.StatusConflict, "r", CodeConflict, "duplicate", map[string][]string{"code": {"taken"}})
	body := getBody(rec)
	e := body["error"].(map[string]any)
	if e["code"] != "CONFLICT" {
		t.Errorf("code = %v", e["code"])
	}
	if rec.Code != http.StatusConflict {
		t.Errorf("status = %d", rec.Code)
	}
}

func TestErrorInternalGenericMessage(t *testing.T) {
	rec := httptest.NewRecorder()
	Internal(rec, "r", stubLogger{}, &whisperError{"sensitive db credentials"})
	body := getBody(rec)
	e := body["error"].(map[string]any)
	if strings.Contains(e["message"].(string), "sensitive") {
		t.Error("internal error message leaked to client: ", e["message"])
	}
	if e["code"] != "INTERNAL_ERROR" {
		t.Errorf("code = %v", e["code"])
	}
}

type whisperError struct{ msg string }

func (e *whisperError) Error() string { return e.msg }

type stubLogger struct{}

func (stubLogger) Error(_ string, _ ...any) {}
