package health

import (
	"context"
	"errors"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"

	"lingniu-vehicle-ingest/go/vehicle-gateway/internal/metrics"
)

func TestHandlerReturnsHealthyWhenAllChecksPass(t *testing.T) {
	handler := NewHandler("vehicle-realtime-api", []Check{
		{Name: "redis", Check: func(context.Context) error { return nil }},
		{Name: "mysql", Check: func(context.Context) error { return nil }},
	})
	request := httptest.NewRequest(http.MethodGet, "/readyz", nil)
	response := httptest.NewRecorder()

	handler.ServeHTTP(response, request)

	if response.Code != http.StatusOK {
		t.Fatalf("status = %d body=%s", response.Code, response.Body.String())
	}
	body := response.Body.String()
	for _, want := range []string{`"service":"vehicle-realtime-api"`, `"status":"ok"`, `"redis":{"status":"ok"`, `"mysql":{"status":"ok"`} {
		if !strings.Contains(body, want) {
			t.Fatalf("response missing %s: %s", want, body)
		}
	}
}

func TestHandlerReturnsServiceUnavailableWhenCheckFails(t *testing.T) {
	handler := NewHandler("vehicle-history-writer", []Check{
		{Name: "tdengine", Check: func(context.Context) error { return errors.New("ping failed") }},
	})
	request := httptest.NewRequest(http.MethodGet, "/readyz", nil)
	response := httptest.NewRecorder()

	handler.ServeHTTP(response, request)

	if response.Code != http.StatusServiceUnavailable {
		t.Fatalf("status = %d body=%s", response.Code, response.Body.String())
	}
	body := response.Body.String()
	for _, want := range []string{`"service":"vehicle-history-writer"`, `"status":"degraded"`, `"tdengine":`, `"status":"error"`, `"error":"ping failed"`} {
		if !strings.Contains(body, want) {
			t.Fatalf("response missing %s: %s", want, body)
		}
	}
}

func TestHandlerRejectsUnknownPath(t *testing.T) {
	handler := NewHandler("vehicle-gateway", nil)
	request := httptest.NewRequest(http.MethodGet, "/metrics", nil)
	response := httptest.NewRecorder()

	handler.ServeHTTP(response, request)

	if response.Code != http.StatusNotFound {
		t.Fatalf("status = %d body=%s", response.Code, response.Body.String())
	}
}

func TestNewMuxRegistersHealthAndReadinessRoutes(t *testing.T) {
	registry := metrics.NewRegistry()
	registry.IncCounter("vehicle_test_total", metrics.Labels{"service": "stat"})
	mux := NewMux("vehicle-stat-writer", []Check{
		{Name: "mysql", Check: func(context.Context) error { return nil }},
	}, registry)
	for _, path := range []string{"/healthz", "/readyz", "/metrics"} {
		request := httptest.NewRequest(http.MethodGet, path, nil)
		response := httptest.NewRecorder()

		mux.ServeHTTP(response, request)

		if response.Code != http.StatusOK {
			t.Fatalf("%s status = %d body=%s", path, response.Code, response.Body.String())
		}
	}

	request := httptest.NewRequest(http.MethodGet, "/metrics", nil)
	response := httptest.NewRecorder()
	mux.ServeHTTP(response, request)
	if !strings.Contains(response.Body.String(), `vehicle_service_info{service="vehicle-stat-writer"} 1`) {
		t.Fatalf("service info metric missing: %s", response.Body.String())
	}
}

func TestNewServerReturnsNilWhenAddressIsEmpty(t *testing.T) {
	if server := NewServer("", "vehicle-gateway", nil, nil); server != nil {
		t.Fatalf("server = %#v, want nil", server)
	}
}

func TestNewServerBuildsConfiguredHTTPServer(t *testing.T) {
	server := NewServer(":20290", "vehicle-gateway", nil, nil)
	if server == nil {
		t.Fatal("server is nil")
	}
	if server.Addr != ":20290" {
		t.Fatalf("addr = %q", server.Addr)
	}
	if server.ReadHeaderTimeout == 0 {
		t.Fatal("ReadHeaderTimeout should be configured")
	}
}
