package store

import (
	"strings"
	"testing"
)

func TestCreateLogScanRule_Validates(t *testing.T) {
	s := newTestStore(t)
	cases := []struct {
		name    string
		in      LogScanRule
		wantErr string
	}{
		{
			name:    "missing name",
			in:      LogScanRule{Pattern: "x"},
			wantErr: "name is required",
		},
		{
			name:    "missing pattern",
			in:      LogScanRule{Name: "n"},
			wantErr: "pattern is required",
		},
		{
			name:    "bad severity",
			in:      LogScanRule{Name: "n", Pattern: "x", Severity: "loud"},
			wantErr: "invalid severity",
		},
		{
			name:    "bad streams",
			in:      LogScanRule{Name: "n", Pattern: "x", Streams: "both"},
			wantErr: "invalid streams",
		},
		{
			name:    "negative cooldown",
			in:      LogScanRule{Name: "n", Pattern: "x", CooldownSeconds: -1},
			wantErr: "cooldown_seconds must be",
		},
		{
			name:    "override without workload",
			in:      LogScanRule{Name: "n", Pattern: "x", OverridesID: 5},
			wantErr: "override row requires workload_id",
		},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			_, err := s.CreateLogScanRule(c.in)
			if err == nil {
				t.Fatalf("expected error containing %q, got nil", c.wantErr)
			}
			if !strings.Contains(err.Error(), c.wantErr) {
				t.Fatalf("error mismatch: got %q want substring %q", err.Error(), c.wantErr)
			}
		})
	}
}

func TestCreateAndGetLogScanRule(t *testing.T) {
	s := newTestStore(t)
	r, err := s.CreateLogScanRule(LogScanRule{
		Name: "panics", Pattern: `\bpanic\b`, Severity: "error", Streams: "stderr",
		CooldownSeconds: 30, Enabled: true,
	})
	if err != nil {
		t.Fatalf("create: %v", err)
	}
	if r.ID == 0 {
		t.Fatal("id should be set")
	}
	got, err := s.GetLogScanRule(r.ID)
	if err != nil {
		t.Fatalf("get: %v", err)
	}
	if got.Pattern != `\bpanic\b` {
		t.Errorf("pattern mismatch: %q", got.Pattern)
	}
	if !got.Enabled {
		t.Error("enabled lost on round-trip")
	}
}

func TestEffectiveLogScanRules(t *testing.T) {
	s := newTestStore(t)
	g, _ := s.CreateLogScanRule(LogScanRule{
		Name: "global", Pattern: "panic", Severity: "warn", Streams: "all", Enabled: true,
	})
	_, _ = s.CreateLogScanRule(LogScanRule{
		Name: "w1-only", Pattern: "slow_query", WorkloadID: "w1", Severity: "info", Streams: "all", Enabled: true,
	})
	_, _ = s.CreateLogScanRule(LogScanRule{
		Name: "override-for-w1", Pattern: "panic", WorkloadID: "w1", OverridesID: g.ID,
		Severity: "error", Streams: "all", Enabled: true,
	})

	w1, err := s.EffectiveLogScanRules("w1")
	if err != nil {
		t.Fatalf("effective w1: %v", err)
	}
	if len(w1) != 2 {
		t.Fatalf("w1 effective should be 2 (override + addition), got %d", len(w1))
	}
	// First entry replaces the global with the override (error severity).
	if w1[0].Severity != "error" {
		t.Errorf("override severity not applied: %q", w1[0].Severity)
	}

	w2, err := s.EffectiveLogScanRules("w2")
	if err != nil {
		t.Fatalf("effective w2: %v", err)
	}
	if len(w2) != 1 {
		t.Fatalf("w2 effective should be 1 (just the global), got %d", len(w2))
	}
	if w2[0].Severity != "warn" {
		t.Errorf("w2 should see original severity: %q", w2[0].Severity)
	}
}

func TestDeleteLogScanRule_CascadesOverrides(t *testing.T) {
	s := newTestStore(t)
	g, _ := s.CreateLogScanRule(LogScanRule{
		Name: "global", Pattern: "panic", Severity: "warn", Streams: "all", Enabled: true,
	})
	ov, _ := s.CreateLogScanRule(LogScanRule{
		Name: "override", Pattern: "panic", WorkloadID: "w1", OverridesID: g.ID,
		Severity: "error", Streams: "all", Enabled: true,
	})

	if err := s.DeleteLogScanRule(g.ID); err != nil {
		t.Fatalf("delete: %v", err)
	}
	if _, err := s.GetLogScanRule(ov.ID); err == nil {
		t.Error("override should be cascade-deleted with its global")
	}
}

func TestUpdateLogScanRule(t *testing.T) {
	s := newTestStore(t)
	r, _ := s.CreateLogScanRule(LogScanRule{
		Name: "n", Pattern: "x", Severity: "warn", Streams: "all", Enabled: true,
	})
	r.Pattern = "y"
	r.Enabled = false
	got, err := s.UpdateLogScanRule(r)
	if err != nil {
		t.Fatalf("update: %v", err)
	}
	if got.Pattern != "y" {
		t.Errorf("pattern not updated: %q", got.Pattern)
	}
	if got.Enabled {
		t.Error("enabled=false not applied")
	}
}
