package tui

import (
	"strings"
	"testing"
	"time"
	"unicode/utf8"
)

func TestLatencySparkline_Empty(t *testing.T) {
	got := latencySparkline(nil, nil, 10, "")
	if !strings.Contains(got, "··········") {
		t.Errorf("empty sparkline should be dots, got %q", got)
	}
}

func TestLatencySparkline_SingleValue(t *testing.T) {
	latencies := []time.Duration{100 * time.Millisecond}
	statuses := []bool{true}
	got := latencySparkline(latencies, statuses, 5, "")
	if len(got) == 0 {
		t.Error("sparkline should not be empty")
	}
	if !strings.Contains(got, "····") {
		t.Errorf("single value with width=5 should have 4 dot padding, got %q", got)
	}
}

func TestLatencySparkline_WidthTruncation(t *testing.T) {
	latencies := make([]time.Duration, 20)
	statuses := make([]bool, 20)
	for i := range latencies {
		latencies[i] = time.Duration(i*50) * time.Millisecond
		statuses[i] = true
	}
	got := latencySparkline(latencies, statuses, 5, "")
	if len(got) == 0 {
		t.Error("sparkline should not be empty")
	}
	if strings.Contains(got, "·") {
		t.Errorf("20 samples in width=5 should have no padding, got %q", got)
	}
}

func TestLatencySparkline_RelativeHeight(t *testing.T) {
	latencies := []time.Duration{10 * time.Millisecond, 50 * time.Millisecond, 10 * time.Millisecond}
	statuses := []bool{true, true, true}
	out := stripANSI(latencySparkline(latencies, statuses, 3, ""))
	runes := []rune(out)
	if len(runes) < 3 {
		t.Fatalf("expected 3 runes, got %d", len(runes))
	}
	if runes[0] == runes[1] {
		t.Errorf("min and max should have different bar heights, got %c %c %c", runes[0], runes[1], runes[2])
	}
}

func TestLatencyStyle_BandsProduceDifferentColors(t *testing.T) {
	sparkSuccess = "#00ff00"
	sparkWarning = "#ffff00"
	sparkDanger = "#ff0000"
	defer func() {
		sparkSuccess = ""
		sparkWarning = ""
		sparkDanger = ""
	}()

	green := latencyStyle(50, "")
	yellow := latencyStyle(300, "")
	red := latencyStyle(800, "")

	gfg := green.GetForeground()
	yfg := yellow.GetForeground()
	rfg := red.GetForeground()

	if gfg == yfg || yfg == rfg || gfg == rfg {
		t.Errorf("bands should produce distinct foreground colors: green=%v yellow=%v red=%v", gfg, yfg, rfg)
	}
}

func TestLatencyStyle_BrightnessVariesWithinBand(t *testing.T) {
	sparkSuccess = "#00ff00"
	defer func() { sparkSuccess = "" }()

	dim := latencyStyle(10, "")
	bright := latencyStyle(190, "")

	if dim.GetForeground() == bright.GetForeground() {
		t.Error("10ms and 190ms should have different brightness within green band")
	}
}

func TestLatencySparkline_OutputWidth(t *testing.T) {
	latencies := []time.Duration{100 * time.Millisecond, 200 * time.Millisecond, 300 * time.Millisecond}
	statuses := []bool{true, true, true}
	got := latencySparkline(latencies, statuses, 5, "")
	count := utf8.RuneCountInString(stripANSI(got))
	if count != 5 {
		t.Errorf("expected 5 rune-width output, got %d from %q", count, got)
	}
}

func stripANSI(s string) string {
	var out strings.Builder
	i := 0
	for i < len(s) {
		if s[i] == '\x1b' {
			for i < len(s) && s[i] != 'm' {
				i++
			}
			i++
			continue
		}
		out.WriteByte(s[i])
		i++
	}
	return out.String()
}

func TestHeartbeatSparkline_Empty(t *testing.T) {
	got := heartbeatSparkline(nil, 10, "")
	if !strings.Contains(got, "··········") {
		t.Errorf("empty heartbeat should be dots, got %q", got)
	}
}

func TestHeartbeatSparkline_Mixed(t *testing.T) {
	statuses := []bool{true, false, true, true, false}
	got := heartbeatSparkline(statuses, 5, "")
	if len(got) == 0 {
		t.Error("heartbeat sparkline should not be empty")
	}
}

func TestHeartbeatSparkline_PaddedWidth(t *testing.T) {
	statuses := []bool{true, true}
	got := heartbeatSparkline(statuses, 5, "")
	if !strings.Contains(got, "···") {
		t.Errorf("should have dot padding for width > data, got %q", got)
	}
}
