package store

import (
	"context"
	"testing"
	"time"
)

// makeSnapHost inserts a minimal host row that snapshot tests can hang
// off. Returns the host id.
func makeSnapHost(t *testing.T, s *Store) string {
	t.Helper()
	const id = "01HSNAPHOST00000000000000"
	if err := s.CreateHost(context.Background(), Host{
		ID: id, Name: "snap-host", OS: "linux", Arch: "amd64",
		AgentVersion: "dev", ResticVersion: "0.16.0", ProtocolVersion: 1,
		EnrolledAt: time.Now().UTC(),
	}, "tokenhash", ""); err != nil {
		t.Fatalf("create host: %v", err)
	}
	return id
}

func TestReplaceHostSnapshotsRoundTrip(t *testing.T) {
	t.Parallel()
	s := openTestStore(t)
	hostID := makeSnapHost(t, s)
	ctx := context.Background()

	now := time.Now().UTC().Truncate(time.Second)
	in := []Snapshot{
		{
			ID:        "deadbeef" + "00000000000000000000000000000000000000000000000000000000",
			ShortID:   "deadbeef",
			Time:      now.Add(-2 * time.Hour),
			Hostname:  "snap-host",
			Paths:     []string{"/etc", "/home"},
			Tags:      []string{"daily"},
			SizeBytes: 4096, FileCount: 12,
		},
		{
			ID:        "cafef00d" + "00000000000000000000000000000000000000000000000000000000",
			ShortID:   "cafef00d",
			Time:      now.Add(-1 * time.Hour),
			Hostname:  "snap-host",
			Paths:     []string{"/etc"},
			SizeBytes: 8192, FileCount: 24,
		},
	}
	if err := s.ReplaceHostSnapshots(ctx, hostID, in, now); err != nil {
		t.Fatalf("replace: %v", err)
	}

	out, err := s.ListSnapshotsByHost(ctx, hostID)
	if err != nil {
		t.Fatalf("list: %v", err)
	}
	if len(out) != 2 {
		t.Fatalf("want 2 snapshots, got %d", len(out))
	}
	// Ordered by time DESC — most recent first.
	if out[0].ShortID != "cafef00d" {
		t.Errorf("want most-recent first; got %q", out[0].ShortID)
	}
	if got := len(out[0].Paths); got != 1 {
		t.Errorf("paths roundtrip lost: %v", out[0].Paths)
	}
	if out[1].Tags == nil || out[1].Tags[0] != "daily" {
		t.Errorf("tags roundtrip lost: %v", out[1].Tags)
	}

	// Host snapshot_count is updated atomically.
	h, err := s.GetHost(ctx, hostID)
	if err != nil {
		t.Fatalf("get host: %v", err)
	}
	if h.SnapshotCount != 2 {
		t.Errorf("host snapshot_count = %d, want 2", h.SnapshotCount)
	}
}

func TestReplaceHostSnapshotsIsAuthoritative(t *testing.T) {
	t.Parallel()
	s := openTestStore(t)
	hostID := makeSnapHost(t, s)
	ctx := context.Background()

	mk := func(id, short string, tOff time.Duration) Snapshot {
		return Snapshot{
			ID: id, ShortID: short, Time: time.Now().UTC().Add(tOff),
			Hostname: "snap-host", Paths: []string{"/x"},
		}
	}
	first := []Snapshot{
		mk("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "aaaaaaaa", -3*time.Hour),
		mk("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", "bbbbbbbb", -2*time.Hour),
		mk("cccccccccccccccccccccccccccccccccccccccccccccccccccccccc", "cccccccc", -1*time.Hour),
	}
	if err := s.ReplaceHostSnapshots(ctx, hostID, first, time.Now().UTC()); err != nil {
		t.Fatalf("replace 1: %v", err)
	}

	// Subsequent forget+prune on the host: only one snapshot remains.
	second := []Snapshot{
		mk("cccccccccccccccccccccccccccccccccccccccccccccccccccccccc", "cccccccc", -1*time.Hour),
	}
	if err := s.ReplaceHostSnapshots(ctx, hostID, second, time.Now().UTC()); err != nil {
		t.Fatalf("replace 2: %v", err)
	}

	out, err := s.ListSnapshotsByHost(ctx, hostID)
	if err != nil {
		t.Fatalf("list: %v", err)
	}
	if len(out) != 1 || out[0].ShortID != "cccccccc" {
		t.Errorf("after second replace, want [cccccccc], got %+v", out)
	}
	h, _ := s.GetHost(ctx, hostID)
	if h.SnapshotCount != 1 {
		t.Errorf("snapshot_count should track replacement: %d", h.SnapshotCount)
	}
}

func TestReplaceHostSnapshotsEmpty(t *testing.T) {
	t.Parallel()
	s := openTestStore(t)
	hostID := makeSnapHost(t, s)
	ctx := context.Background()

	// First a non-empty replace.
	if err := s.ReplaceHostSnapshots(ctx, hostID, []Snapshot{
		{
			ID:      "1111111111111111111111111111111111111111111111111111111111111111",
			ShortID: "11111111", Time: time.Now().UTC(), Hostname: "snap-host",
			Paths: []string{"/x"},
		},
	}, time.Now().UTC()); err != nil {
		t.Fatalf("replace 1: %v", err)
	}
	// Then empty — host has been wiped.
	if err := s.ReplaceHostSnapshots(ctx, hostID, nil, time.Now().UTC()); err != nil {
		t.Fatalf("replace empty: %v", err)
	}
	out, err := s.ListSnapshotsByHost(ctx, hostID)
	if err != nil {
		t.Fatalf("list: %v", err)
	}
	if len(out) != 0 {
		t.Errorf("want empty, got %d", len(out))
	}
	h, _ := s.GetHost(ctx, hostID)
	if h.SnapshotCount != 0 {
		t.Errorf("snapshot_count should reset to 0, got %d", h.SnapshotCount)
	}
}
