package scheduler

import (
	"testing"
)

func TestParsePingLatency(t *testing.T) {
	cases := []struct {
		name string
		out  []byte
		want float64
	}{
		{
			name: "linux rtt format",
			out:  []byte("PING host (1.2.3.4): 56 data bytes\n--- host ping statistics ---\n5 packets transmitted, 5 received, 0% packet loss\nrtt min/avg/max/mdev = 0.1/2.5/5.0/1.2 ms\n"),
			want: 2.5,
		},
		{
			name: "macos round-trip format",
			out:  []byte("PING host (1.2.3.4): 56 data bytes\n--- host ping statistics ---\n5 packets transmitted, 5 received, 0% packet loss\nround-trip min/avg/max/stddev = 0.1/2.5/5.0/1.2 ms\n"),
			want: 2.5,
		},
		{
			name: "no match empty string",
			out:  []byte(""),
			want: 0,
		},
		{
			name: "malformed number in avg slot",
			out:  []byte("rtt min/avg/max/mdev = 0.1/abc/5.0/1.2 ms\n"),
			want: 0,
		},
		{
			name: "truly empty input nil",
			out:  nil,
			want: 0,
		},
		{
			name: "linux integer avg",
			out:  []byte("rtt min/avg/max/mdev = 1/3/5/0.5 ms\n"),
			want: 3.0,
		},
	}

	for _, tc := range cases {
		t.Run(tc.name, func(t *testing.T) {
			got := parsePingLatency(tc.out)
			if got != tc.want {
				t.Fatalf("parsePingLatency(%q) = %v, want %v", tc.out, got, tc.want)
			}
		})
	}
}

func TestAllowlistedScript(t *testing.T) {
	cases := []struct {
		name string
		in   string
		want bool
	}{
		{name: "cpu_check.sh", in: "cpu_check.sh", want: true},
		{name: "disk_usage_check.sh", in: "disk_usage_check.sh", want: true},
		{name: "hyphen allowed", in: "foo-bar.sh", want: true},
		{name: "underscore allowed", in: "foo_bar.sh", want: true},
		{name: "uppercase rejected", in: "Foo.sh", want: false},
		{name: "bare .sh rejected (no name)", in: ".sh", want: false},
		{name: "path traversal rejected", in: "../etc/passwd", want: false},
		{name: "empty rejected", in: "", want: false},
		// foo.sh.sh: regex ^[a-z][a-z0-9_-]+\.sh$ — the [a-z0-9_-]+ cannot
		// cross the first '.', so after matching "foo.sh" the trailing ".sh"
		// breaks the $ anchor → no match.
		{name: "doubled .sh.sh rejected", in: "foo.sh.sh", want: false},
		{name: "wrong extension rejected", in: "foo.txt", want: false},
		{name: "single char name rejected (needs 2+)", in: "a.sh", want: false},
		{name: "two char name accepted", in: "ab.sh", want: true},
		{name: "digit after first char", in: "a1.sh", want: true},
		{name: "leading digit rejected", in: "1foo.sh", want: false},
		{name: "dot in middle rejected", in: "foo.bar.sh", want: false},
		{name: "space rejected", in: "foo bar.sh", want: false},
	}

	for _, tc := range cases {
		t.Run(tc.name, func(t *testing.T) {
			got := allowlistedScript(tc.in)
			if got != tc.want {
				t.Fatalf("allowlistedScript(%q) = %v, want %v", tc.in, got, tc.want)
			}
		})
	}
}

func TestEvaluateSeverity(t *testing.T) {
	cases := []struct {
		name       string
		kind       string
		signalKind string
		config     []byte
		metrics    map[string]float64
		want       string
	}{
		{
			name:       "empty config down signal",
			kind:       "ping",
			signalKind: "down",
			config:     nil,
			metrics:    map[string]float64{},
			want:       "critical",
		},
		{
			name:       "empty config high_temp signal",
			kind:       "ssh-script",
			signalKind: "high_temp",
			config:     nil,
			metrics:    map[string]float64{},
			want:       "warning",
		},
		{
			name:       "crit only exceeded",
			kind:       "ssh-script",
			signalKind: "high_temp",
			config:     []byte(`{"temp":{"crit":90}}`),
			metrics:    map[string]float64{"temp": 95},
			want:       "critical",
		},
		{
			name:       "warn only exceeded",
			kind:       "ssh-script",
			signalKind: "high_temp",
			config:     []byte(`{"temp":{"warn":80}}`),
			metrics:    map[string]float64{"temp": 85},
			want:       "warning",
		},
		{
			name:       "warn and crit, warn exceeded only",
			kind:       "ssh-script",
			signalKind: "high_temp",
			config:     []byte(`{"temp":{"warn":80,"crit":90}}`),
			metrics:    map[string]float64{"temp": 85},
			want:       "warning",
		},
		{
			name:       "warn and crit, crit exceeded",
			kind:       "ssh-script",
			signalKind: "high_temp",
			config:     []byte(`{"temp":{"warn":80,"crit":90}}`),
			metrics:    map[string]float64{"temp": 95},
			want:       "critical",
		},
		{
			name:       "metric below thresholds falls through to warning",
			kind:       "ssh-script",
			signalKind: "high_temp",
			config:     []byte(`{"temp":{"warn":80,"crit":90}}`),
			metrics:    map[string]float64{"temp": 70},
			want:       "warning",
		},
		{
			name:       "metric below thresholds falls through to down critical",
			kind:       "ping",
			signalKind: "down",
			config:     []byte(`{"ping_latency_ms":{"warn":100,"crit":200}}`),
			metrics:    map[string]float64{"ping_latency_ms": 50},
			want:       "critical",
		},
		{
			name:       "crit zero skipped falls through",
			kind:       "ssh-script",
			signalKind: "high_temp",
			config:     []byte(`{"temp":{"crit":0}}`),
			metrics:    map[string]float64{"temp": 95},
			want:       "warning",
		},
		{
			name:       "metric not in thresholds ignored",
			kind:       "ssh-script",
			signalKind: "high_temp",
			config:     []byte(`{"temp":{"warn":80,"crit":90}}`),
			metrics:    map[string]float64{"cpu": 99},
			want:       "warning",
		},
		{
			name:       "equal to warn triggers warning",
			kind:       "ssh-script",
			signalKind: "high_temp",
			config:     []byte(`{"temp":{"warn":80,"crit":90}}`),
			metrics:    map[string]float64{"temp": 80},
			want:       "warning",
		},
		{
			name:       "equal to crit triggers critical",
			kind:       "ssh-script",
			signalKind: "high_temp",
			config:     []byte(`{"temp":{"warn":80,"crit":90}}`),
			metrics:    map[string]float64{"temp": 90},
			want:       "critical",
		},
	}

	for _, tc := range cases {
		t.Run(tc.name, func(t *testing.T) {
			got := evaluateSeverity(tc.kind, tc.signalKind, tc.config, tc.metrics)
			if got != tc.want {
				t.Fatalf("evaluateSeverity(%q, %q, %s, %v) = %q, want %q",
					tc.kind, tc.signalKind, tc.config, tc.metrics, got, tc.want)
			}
		})
	}
}
