package dbsync

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

func TestCheckpointSaveRestoreRoundTrip(t *testing.T) {
	dir := t.TempDir()
	store, err := NewFileStore(dir)
	if err != nil {
		t.Fatal(err)
	}
	remoteDSN := "file:" + filepath.ToSlash(filepath.Join(dir, "online.db")) + "?_pragma=busy_timeout(5000)"
	ch := &Channel{
		ID:       "ch-cp-1",
		TenantID: 1,
		Name:     "test",
		Remote: Endpoint{
			Driver: DriverSQLite,
			DSN:    remoteDSN,
		},
		PKColumns: map[string]string{"demo": "id"},
	}
	ctx := context.Background()
	db, err := Open(DriverSQLite, remoteDSN)
	if err != nil {
		t.Fatal(err)
	}
	t.Cleanup(func() {
		_ = db.Close()
		InvalidateRemote(DriverSQLite, remoteDSN)
	})
	if _, err := db.ExecContext(ctx, `CREATE TABLE demo (id TEXT PRIMARY KEY, name TEXT)`); err != nil {
		t.Fatal(err)
	}
	if _, err := db.ExecContext(ctx, `INSERT INTO demo(id,name) VALUES('a','one'),('b','two')`); err != nil {
		t.Fatal(err)
	}
	if err := EnsureMeta(ctx, db, DriverSQLite); err != nil {
		t.Fatal(err)
	}

	if err := SaveCheckpoint(ctx, store, ch, "test"); err != nil {
		t.Fatal(err)
	}
	meta, err := LoadCheckpointMeta(store, ch.ID)
	if err != nil || meta.Latest == nil || meta.Latest.RowCount != 2 {
		t.Fatalf("meta=%+v err=%v", meta, err)
	}

	// mutate then restore
	if _, err := db.ExecContext(ctx, `DELETE FROM demo WHERE id='a'`); err != nil {
		t.Fatal(err)
	}
	if _, err := db.ExecContext(ctx, `INSERT INTO demo(id,name) VALUES('c','three')`); err != nil {
		t.Fatal(err)
	}
	res, err := RestoreCheckpoint(ctx, store, ch, "latest")
	if err != nil {
		t.Fatal(err)
	}
	if !res.OK || res.Upserted < 2 {
		t.Fatalf("restore=%+v", res)
	}
	var n int
	if err := db.QueryRowContext(ctx, `SELECT COUNT(*) FROM demo`).Scan(&n); err != nil || n != 2 {
		t.Fatalf("count=%d err=%v", n, err)
	}
	var name string
	if err := db.QueryRowContext(ctx, `SELECT name FROM demo WHERE id='a'`).Scan(&name); err != nil || name != "one" {
		t.Fatalf("row a name=%q err=%v", name, err)
	}

	// second save rotates
	time.Sleep(10 * time.Millisecond)
	if _, err := db.ExecContext(ctx, `UPDATE demo SET name='one2' WHERE id='a'`); err != nil {
		t.Fatal(err)
	}
	if err := SaveCheckpoint(ctx, store, ch, "test2"); err != nil {
		t.Fatal(err)
	}
	meta2, _ := LoadCheckpointMeta(store, ch.ID)
	if meta2.Previous == nil || meta2.Previous.RowCount != 2 {
		t.Fatalf("expected previous after rotate: %+v", meta2)
	}
}
