package health

import (
	"context"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
)

// TestNewChecker tests the creation of a new health checker
func TestNewChecker(t *testing.T) {
	checker := NewChecker(nil)
	assert.NotNil(t, checker)
	assert.Equal(t, 30*time.Second, checker.checkInterval)
}

// TestCheckWithNilClient tests health check with nil client
func TestCheckWithNilClient(t *testing.T) {
	checker := NewChecker(nil)
	report := checker.Check(context.Background())

	assert.NotNil(t, report)
	assert.Equal(t, StatusUnhealthy, report.Status)
	assert.Len(t, report.Components, 1)
	assert.Equal(t, StatusUnhealthy, report.Components["temporal"].Status)
	assert.Equal(t, "Temporal client not initialized", report.Components["temporal"].Error)
}

// TestIsHealthy tests the IsHealthy method
func TestIsHealthy(t *testing.T) {
	checker := NewChecker(nil)
	assert.False(t, checker.IsHealthy(context.Background()))
}

// TestGetReport tests the GetReport method
func TestGetReport(t *testing.T) {
	checker := NewChecker(nil)
	report := checker.GetReport(context.Background())
	assert.NotNil(t, report)
	assert.Equal(t, StatusUnhealthy, report.Status)
}

// TestHealthReportJSON tests JSON serialization
func TestHealthReportJSON(t *testing.T) {
	checker := NewChecker(nil)
	report := checker.Check(context.Background())

	jsonData, err := report.ToJSON()
	assert.NoError(t, err)
	assert.NotEmpty(t, jsonData)
	assert.Contains(t, string(jsonData), "unhealthy")
	assert.Contains(t, string(jsonData), "temporal")
}

// TestHealthReportTimestamp tests that timestamp is set
func TestHealthReportTimestamp(t *testing.T) {
	checker := NewChecker(nil)
	before := time.Now()
	report := checker.Check(context.Background())
	after := time.Now()

	assert.True(t, report.Timestamp.After(before) || report.Timestamp.Equal(before))
	assert.True(t, report.Timestamp.Before(after) || report.Timestamp.Equal(after))
}

// TestStatusString tests Status string representation
func TestStatusString(t *testing.T) {
	assert.Equal(t, "healthy", StatusHealthy.String())
	assert.Equal(t, "unhealthy", StatusUnhealthy.String())
	assert.Equal(t, "unknown", StatusUnknown.String())
}

// TestComponentHealthLatency tests that latency is recorded
func TestComponentHealthLatency(t *testing.T) {
	checker := NewChecker(nil)
	report := checker.Check(context.Background())

	assert.NotNil(t, report.Components["temporal"])
	assert.GreaterOrEqual(t, report.Components["temporal"].Latency, int64(0))
}

// TestHealthCheckCaching tests that recent checks are cached
func TestHealthCheckCaching(t *testing.T) {
	checker := NewChecker(nil)

	// First check
	report1 := checker.Check(context.Background())
	time1 := report1.Timestamp

	// Second check immediately (should be cached)
	time.Sleep(100 * time.Millisecond)
	report2 := checker.Check(context.Background())
	time2 := report2.Timestamp

	// Timestamps should be the same or very close (cached)
	assert.Equal(t, time1, time2, "second check should use cached result")
}

// TestComponentHealthDefaults tests default component health values
func TestComponentHealthDefaults(t *testing.T) {
	comp := ComponentHealth{
		Name:   "test",
		Status: StatusHealthy,
	}

	assert.Equal(t, "test", comp.Name)
	assert.Equal(t, StatusHealthy, comp.Status)
	assert.Empty(t, comp.Error)
}
