package store

import (
	"strings"
	"testing"
)

func mustCreateWorkload(t *testing.T, s *Store, name string) Workload {
	t.Helper()
	w, err := s.CreateWorkload(Workload{
		Name:        name,
		Kind:        "plugin",
		RefID:       name,
		SourceKind:  "image",
		TriggerKind: "manual",
	})
	if err != nil {
		t.Fatalf("CreateWorkload(%s): %v", name, err)
	}
	return w
}

func TestSetWorkloadEnvUpsertSameKey(t *testing.T) {
	s := newTestStore(t)
	w := mustCreateWorkload(t, s, "envwl")

	first, err := s.SetWorkloadEnv(WorkloadEnv{
		WorkloadID: w.ID, Key: "DB_URL", Value: "v1",
	})
	if err != nil {
		t.Fatalf("first set: %v", err)
	}
	second, err := s.SetWorkloadEnv(WorkloadEnv{
		WorkloadID: w.ID, Key: "DB_URL", Value: "v2", Encrypted: true,
	})
	if err != nil {
		t.Fatalf("second set: %v", err)
	}

	// Same row ID — UPSERT must preserve identity, not accumulate rows.
	if first.ID != second.ID {
		t.Errorf("upsert produced new row: first=%s second=%s", first.ID, second.ID)
	}

	all, err := s.ListWorkloadEnv(w.ID)
	if err != nil {
		t.Fatalf("ListWorkloadEnv: %v", err)
	}
	if len(all) != 1 {
		t.Fatalf("expected 1 row after upsert, got %d", len(all))
	}
	if all[0].Value != "v2" || !all[0].Encrypted {
		t.Errorf("expected upserted value+encrypted, got value=%q encrypted=%v",
			all[0].Value, all[0].Encrypted)
	}
}

func TestSetWorkloadEnvValidation(t *testing.T) {
	s := newTestStore(t)
	w := mustCreateWorkload(t, s, "validate-wl")

	if _, err := s.SetWorkloadEnv(WorkloadEnv{Key: "X"}); err == nil {
		t.Fatal("expected error when WorkloadID missing")
	}
	if _, err := s.SetWorkloadEnv(WorkloadEnv{WorkloadID: w.ID}); err == nil {
		t.Fatal("expected error when Key missing")
	}
}

func TestDeleteWorkloadEnv(t *testing.T) {
	s := newTestStore(t)
	w := mustCreateWorkload(t, s, "delete-wl")
	row, _ := s.SetWorkloadEnv(WorkloadEnv{WorkloadID: w.ID, Key: "K", Value: "V"})

	if err := s.DeleteWorkloadEnv(row.ID); err != nil {
		t.Fatalf("delete: %v", err)
	}
	if err := s.DeleteWorkloadEnv(row.ID); err == nil {
		t.Fatal("expected ErrNotFound on second delete")
	} else if !strings.Contains(err.Error(), "not found") {
		t.Errorf("expected not-found error, got %v", err)
	}
}

func TestListChildrenByParent(t *testing.T) {
	s := newTestStore(t)

	parent := mustCreateWorkload(t, s, "parent")
	other := mustCreateWorkload(t, s, "other-root")

	// Two children of parent, plus one root unrelated.
	for _, name := range []string{"child-a", "child-b"} {
		c, err := s.CreateWorkload(Workload{
			Name:             name,
			Kind:             "plugin",
			RefID:            name,
			SourceKind:       "image",
			TriggerKind:      "manual",
			ParentWorkloadID: parent.ID,
		})
		if err != nil {
			t.Fatalf("create child %s: %v", name, err)
		}
		_ = c
	}

	got, err := s.ListChildrenByParent(parent.ID)
	if err != nil {
		t.Fatalf("ListChildrenByParent: %v", err)
	}
	if len(got) != 2 {
		t.Fatalf("expected 2 children, got %d", len(got))
	}
	if got[0].Name >= got[1].Name {
		t.Errorf("expected name-ordered output, got %q then %q", got[0].Name, got[1].Name)
	}

	// The unrelated workload must not appear.
	for _, c := range got {
		if c.ID == other.ID {
			t.Errorf("ListChildrenByParent leaked unrelated workload %s", other.ID)
		}
	}

	// Empty parent returns empty slice, not error.
	empty, err := s.ListChildrenByParent("")
	if err != nil {
		t.Fatalf("empty parent should not error: %v", err)
	}
	if len(empty) != 0 {
		t.Errorf("empty parent should return 0 rows, got %d", len(empty))
	}
}
