package monitoring_test

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

	"github.com/gin-gonic/gin"
	"github.com/glebarez/sqlite"
	"gorm.io/gorm"

	"github.com/user-management-system/internal/monitoring"
)

func TestHealthCheckReadinessHandlerReturnsServiceUnavailableWhenDatabaseMissing(t *testing.T) {
	gin.SetMode(gin.TestMode)

	healthCheck := monitoring.NewHealthCheck(nil)
	recorder := httptest.NewRecorder()
	ctx, _ := gin.CreateTestContext(recorder)
	ctx.Request = httptest.NewRequest(http.MethodGet, "/health/ready", nil)

	healthCheck.ReadinessHandler(ctx)

	if recorder.Code != http.StatusServiceUnavailable {
		t.Fatalf("expected 503, got %d", recorder.Code)
	}

	var status monitoring.Status
	if err := json.Unmarshal(recorder.Body.Bytes(), &status); err != nil {
		t.Fatalf("failed to decode response: %v", err)
	}
	if status.Status != monitoring.HealthStatusDOWN {
		t.Fatalf("expected DOWN, got %s", status.Status)
	}
	if check := status.Checks["database"]; check.Status != monitoring.HealthStatusDOWN {
		t.Fatalf("expected database check to be DOWN, got %s", check.Status)
	}
}

func TestHealthCheckReadinessHandlerReturnsOKWhenDatabaseIsReady(t *testing.T) {
	gin.SetMode(gin.TestMode)

	db, err := gorm.Open(sqlite.Open("file::memory:?cache=shared"), &gorm.Config{})
	if err != nil {
		t.Fatalf("failed to open sqlite database: %v", err)
	}

	healthCheck := monitoring.NewHealthCheck(db)
	recorder := httptest.NewRecorder()
	ctx, _ := gin.CreateTestContext(recorder)
	ctx.Request = httptest.NewRequest(http.MethodGet, "/health/ready", nil)

	healthCheck.ReadinessHandler(ctx)

	if recorder.Code != http.StatusOK {
		t.Fatalf("expected 200, got %d", recorder.Code)
	}
}

func TestHealthCheckLivenessHandlerReturnsNoContent(t *testing.T) {
	gin.SetMode(gin.TestMode)

	healthCheck := monitoring.NewHealthCheck(nil)
	recorder := httptest.NewRecorder()
	ctx, _ := gin.CreateTestContext(recorder)
	ctx.Request = httptest.NewRequest(http.MethodGet, "/health/live", nil)

	healthCheck.LivenessHandler(ctx)

	if recorder.Code != http.StatusNoContent {
		t.Fatalf("expected 204, got %d", recorder.Code)
	}
	if recorder.Body.Len() != 0 {
		t.Fatalf("expected empty body, got %q", recorder.Body.String())
	}
}
