package store

import (
	"errors"
	"testing"
)

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

func TestDeployHistory_InsertListGet(t *testing.T) {
	s := newTestStore(t)
	w := seedWorkload(t, s, "app1")

	first, err := s.InsertDeployHistory(DeployHistoryEntry{
		WorkloadID: w.ID, SourceKind: "image", Reference: "v1",
		Reason: "manual", TriggeredBy: "admin", Outcome: "success",
	})
	if err != nil {
		t.Fatalf("InsertDeployHistory: %v", err)
	}
	if first.ID == 0 {
		t.Fatal("expected non-zero id")
	}
	if first.StartedAt == "" || first.FinishedAt == "" {
		t.Fatal("expected timestamps to be defaulted")
	}

	second, _ := s.InsertDeployHistory(DeployHistoryEntry{
		WorkloadID: w.ID, SourceKind: "image", Reference: "v2",
		Reason: "registry-push", Outcome: "success",
	})

	list, err := s.ListDeployHistory(w.ID, 10, 0)
	if err != nil {
		t.Fatalf("ListDeployHistory: %v", err)
	}
	if len(list) != 2 {
		t.Fatalf("expected 2 rows, got %d", len(list))
	}
	// Newest-first ordering.
	if list[0].ID != second.ID || list[1].ID != first.ID {
		t.Fatalf("expected newest-first ordering, got %d then %d", list[0].ID, list[1].ID)
	}

	got, err := s.GetDeployHistory(first.ID)
	if err != nil {
		t.Fatalf("GetDeployHistory: %v", err)
	}
	if got.Reference != "v1" || got.SourceKind != "image" {
		t.Fatalf("unexpected row: %+v", got)
	}
}

func TestDeployHistory_GetNotFound(t *testing.T) {
	s := newTestStore(t)
	_, err := s.GetDeployHistory(999)
	if !errors.Is(err, ErrNotFound) {
		t.Fatalf("expected ErrNotFound, got %v", err)
	}
}

func TestDeployHistory_ListScopedToWorkload(t *testing.T) {
	s := newTestStore(t)
	a := seedWorkload(t, s, "a")
	b := seedWorkload(t, s, "b")
	s.InsertDeployHistory(DeployHistoryEntry{WorkloadID: a.ID, Outcome: "success"})
	s.InsertDeployHistory(DeployHistoryEntry{WorkloadID: b.ID, Outcome: "success"})

	list, _ := s.ListDeployHistory(a.ID, 10, 0)
	if len(list) != 1 || list[0].WorkloadID != a.ID {
		t.Fatalf("expected only workload a's rows, got %+v", list)
	}
}

func TestDeployHistory_Pagination(t *testing.T) {
	s := newTestStore(t)
	w := seedWorkload(t, s, "paged")
	for i := 0; i < 5; i++ {
		s.InsertDeployHistory(DeployHistoryEntry{WorkloadID: w.ID, Outcome: "success"})
	}
	page1, _ := s.ListDeployHistory(w.ID, 2, 0)
	page2, _ := s.ListDeployHistory(w.ID, 2, 2)
	if len(page1) != 2 || len(page2) != 2 {
		t.Fatalf("expected 2 per page, got %d and %d", len(page1), len(page2))
	}
	if page1[0].ID == page2[0].ID {
		t.Fatal("expected distinct rows across pages")
	}
}

func TestDeployHistory_Prune(t *testing.T) {
	s := newTestStore(t)
	w := seedWorkload(t, s, "noisy")
	for i := 0; i < 10; i++ {
		s.InsertDeployHistory(DeployHistoryEntry{WorkloadID: w.ID, Outcome: "success"})
	}
	if err := s.PruneDeployHistory(w.ID, 3); err != nil {
		t.Fatalf("PruneDeployHistory: %v", err)
	}
	list, _ := s.ListDeployHistory(w.ID, 100, 0)
	if len(list) != 3 {
		t.Fatalf("expected 3 rows after prune, got %d", len(list))
	}
	// Prune keeps the newest rows.
	all, _ := s.ListDeployHistory(w.ID, 100, 0)
	for i := 1; i < len(all); i++ {
		if all[i-1].ID < all[i].ID {
			t.Fatal("expected newest-first after prune")
		}
	}
}

func TestDeployHistory_CascadeOnWorkloadDelete(t *testing.T) {
	s := newTestStore(t)
	w := seedWorkload(t, s, "doomed")
	s.InsertDeployHistory(DeployHistoryEntry{WorkloadID: w.ID, Outcome: "success"})
	s.InsertDeployHistory(DeployHistoryEntry{WorkloadID: w.ID, Outcome: "failure"})

	if err := s.DeleteWorkload(w.ID); err != nil {
		t.Fatalf("DeleteWorkload: %v", err)
	}
	list, _ := s.ListDeployHistory(w.ID, 100, 0)
	if len(list) != 0 {
		t.Fatalf("expected history removed with workload, got %d rows", len(list))
	}
}
