package storage

import "testing"

func seedStory(t *testing.T, guid string) int64 {
	t.Helper()
	s := &Story{
		GUID:       guid,
		Headline:   "Headline " + guid,
		Lede:       "Lede.",
		ArticleURL: "https://example.com/" + guid,
		Source:     "Test Source",
		Channel:    "tech",
		Classified: true,
		SeenAt:     1700000000,
	}
	if err := InsertStory(s); err != nil {
		t.Fatalf("insert story %s: %v", guid, err)
	}
	var id int64
	if err := Get().QueryRow(`SELECT id FROM stories WHERE guid = ?`, guid).Scan(&id); err != nil {
		t.Fatalf("lookup id %s: %v", guid, err)
	}
	return id
}

func TestUserStoryState_ReadAndBookmark(t *testing.T) {
	setupTestDB(t)
	id1 := seedStory(t, "s1")
	id2 := seedStory(t, "s2")
	const sub = "ak-sub-1"

	// Nothing set yet.
	read, marks, err := UserStoryState(sub, []int64{id1, id2})
	if err != nil {
		t.Fatalf("initial state: %v", err)
	}
	if len(read) != 0 || len(marks) != 0 {
		t.Fatalf("expected empty state, got read=%v bookmarked=%v", read, marks)
	}

	// Mark id1 read, bookmark id1 and id2.
	if err := SetRead(sub, id1, true); err != nil {
		t.Fatalf("set read: %v", err)
	}
	if err := SetBookmark(sub, id1, true); err != nil {
		t.Fatalf("set bookmark id1: %v", err)
	}
	if err := SetBookmark(sub, id2, true); err != nil {
		t.Fatalf("set bookmark id2: %v", err)
	}
	read, marks, _ = UserStoryState(sub, []int64{id1, id2})
	if !read[id1] || read[id2] {
		t.Fatalf("read map wrong: %v", read)
	}
	if !marks[id1] || !marks[id2] {
		t.Fatalf("bookmark map wrong: %v", marks)
	}
	// id1 carries both flags in a single row.
	if !read[id1] || !marks[id1] {
		t.Fatalf("expected id1 read+bookmarked, read=%v marks=%v", read, marks)
	}

	// ListBookmarks orders newest bookmark first, tiebreaking on story id so the
	// result is deterministic within a single second.
	bm, err := ListBookmarks(sub, 10, 0)
	if err != nil {
		t.Fatalf("list bookmarks: %v", err)
	}
	if len(bm) != 2 {
		t.Fatalf("expected 2 bookmarks, got %d", len(bm))
	}
	if bm[0].ID != id2 || bm[1].ID != id1 {
		t.Fatalf("bookmark order wrong: %d then %d", bm[0].ID, bm[1].ID)
	}
	if n, _ := CountBookmarks(sub); n != 2 {
		t.Fatalf("count bookmarks = %d, want 2", n)
	}
}

func TestUserStoryState_ClearRemovesRow(t *testing.T) {
	setupTestDB(t)
	id := seedStory(t, "s1")
	const sub = "ak-sub-1"

	if err := SetRead(sub, id, true); err != nil {
		t.Fatalf("set read: %v", err)
	}
	if err := SetRead(sub, id, false); err != nil {
		t.Fatalf("unset read: %v", err)
	}
	// Row should be gone since neither flag is set.
	var n int
	if err := Get().QueryRow(`SELECT COUNT(*) FROM user_story_state WHERE user_sub = ?`, sub).Scan(&n); err != nil {
		t.Fatalf("count rows: %v", err)
	}
	if n != 0 {
		t.Fatalf("expected row pruned, found %d", n)
	}

	// Setting read then bookmark then clearing only read must keep the row.
	_ = SetRead(sub, id, true)
	_ = SetBookmark(sub, id, true)
	_ = SetRead(sub, id, false)
	read, marks, _ := UserStoryState(sub, []int64{id})
	if read[id] {
		t.Fatalf("expected not read")
	}
	if !marks[id] {
		t.Fatalf("expected still bookmarked after clearing read")
	}
}

func TestUserStoryState_ScopedBySub(t *testing.T) {
	setupTestDB(t)
	id := seedStory(t, "s1")
	_ = SetBookmark("user-a", id, true)

	read, marks, _ := UserStoryState("user-b", []int64{id})
	if len(read) != 0 || len(marks) != 0 {
		t.Fatalf("user-b should see no state, got read=%v marks=%v", read, marks)
	}
	if n, _ := CountBookmarks("user-b"); n != 0 {
		t.Fatalf("user-b count = %d, want 0", n)
	}
}
