package store

import (
	"context"
	"database/sql"
	"path/filepath"
	"testing"
	"time"
)

// A wipe has to leave a working, empty install: every table still there, every
// migration still applied, and not one row of his anywhere (Vikunja #494).
func TestWipeEmptiesEveryTableAndLeavesTheSchemaUsable(t *testing.T) {
	ctx := context.Background()
	path := filepath.Join(t.TempDir(), "wipe.db")
	s, err := Open(ctx, path)
	if err != nil {
		t.Fatal(err)
	}
	defer s.Close()

	now := time.Now()
	if _, err := s.WriteFact(ctx, now, KindSelf, "monitor", "новый", "tap:test", 1, sql.NullInt64{}); err != nil {
		t.Fatal(err)
	}
	if _, err := s.WriteNote(ctx, now, "купил монитор", []float32{0.1, 0.2}, "tap:test"); err != nil {
		t.Fatal(err)
	}
	if _, err := s.CaptureTask(ctx, Task{Text: "вернуть монитор", Source: "tap:test", Status: TaskOpen, CreatedTs: now}); err != nil {
		t.Fatal(err)
	}

	before, err := s.WipeCounts(ctx)
	if err != nil {
		t.Fatal(err)
	}
	populated := 0
	for _, c := range before {
		if c.Rows > 0 {
			populated++
		}
	}
	if populated == 0 {
		t.Fatal("nothing was written, so the wipe proves nothing")
	}

	if err := s.Wipe(ctx); err != nil {
		t.Fatal(err)
	}

	after, err := s.WipeCounts(ctx)
	if err != nil {
		t.Fatal(err)
	}
	if len(after) != len(before) {
		t.Errorf("table count changed across the wipe: %d before, %d after", len(before), len(after))
	}
	for _, c := range after {
		if c.Rows != 0 {
			t.Errorf("table %s still holds %d rows after the wipe", c.Table, c.Rows)
		}
	}

	// The migrations are what make the schema usable, so the check that matters
	// is a write through the newest columns, not a version number.
	if _, err := s.CaptureTask(ctx, Task{Text: "новая задача", Source: "tap:test", Status: TaskOpen, CreatedTs: now}); err != nil {
		t.Errorf("the store is not usable after a wipe: %v", err)
	}
	if _, err := s.WriteFact(ctx, now, KindSelf, "monitor", "другой", "tap:test", 1, sql.NullInt64{}); err != nil {
		t.Errorf("the store is not usable after a wipe: %v", err)
	}
}

// A wipe that reports success while leaving a table behind is the failure the
// drop-everything approach exists to prevent, so the count has to see the
// tables migrations added, not only the ones schema.sql declares.
func TestWipeCountsSeeMigratedTables(t *testing.T) {
	ctx := context.Background()
	s, err := Open(ctx, filepath.Join(t.TempDir(), "counts.db"))
	if err != nil {
		t.Fatal(err)
	}
	defer s.Close()

	counts, err := s.WipeCounts(ctx)
	if err != nil {
		t.Fatal(err)
	}
	seen := map[string]bool{}
	for _, c := range counts {
		seen[c.Table] = true
	}
	// One from schema.sql, three from migrations, one from a table rebuild.
	for _, want := range []string{"facts", "memory_vectors", "tasks", "ecosystem_traces", "nudges"} {
		if !seen[want] {
			t.Errorf("wipe does not see table %s", want)
		}
	}
}
