package ping

import (
	"context"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"testing"

	"apps/backend/internal/response"
	"apps/backend/internal/svc"
)

type fakeRedisHealth bool

func (f fakeRedisHealth) PingCtx(context.Context) bool { return bool(f) }

func TestRedisUnavailableReturnsServiceUnavailable(t *testing.T) {
	serviceContext := &svc.ServiceContext{Redis: fakeRedisHealth(false)}
	tests := []struct {
		name    string
		handler http.HandlerFunc
	}{
		{name: "ping", handler: PingHandler(serviceContext)},
		{name: "health", handler: HealthHandler(serviceContext)},
	}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			recorder := httptest.NewRecorder()
			test.handler.ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, "/api/v1/"+test.name, nil))
			if recorder.Code != http.StatusServiceUnavailable {
				t.Fatalf("status = %d, want %d", recorder.Code, http.StatusServiceUnavailable)
			}
			var envelope response.Envelope
			if err := json.Unmarshal(recorder.Body.Bytes(), &envelope); err != nil {
				t.Fatal(err)
			}
			if envelope.Code != 503001 || envelope.Message != "redis unavailable" {
				t.Fatalf("response = %#v", envelope)
			}
		})
	}
}

func TestRedisAvailableKeepsPingContract(t *testing.T) {
	serviceContext := &svc.ServiceContext{Redis: fakeRedisHealth(true)}
	recorder := httptest.NewRecorder()
	PingHandler(serviceContext).ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, "/api/v1/ping", nil))
	if recorder.Code != http.StatusOK {
		t.Fatalf("status = %d, want %d", recorder.Code, http.StatusOK)
	}
	var envelope response.Envelope
	if err := json.Unmarshal(recorder.Body.Bytes(), &envelope); err != nil {
		t.Fatal(err)
	}
	if envelope.Code != 102000 {
		t.Fatalf("code = %d, want 102000", envelope.Code)
	}
}
