package storage

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

	"github.com/prometheus/client_golang/prometheus"
	"github.com/seaweedfs/seaweedfs/telemetry/proto"
)

func TestStateRoundTrip(t *testing.T) {
	path := filepath.Join(t.TempDir(), "data", "telemetry-state.json")

	s := newPrometheusStorage(prometheus.NewRegistry())

	if err := s.SaveStateIfDirty(path); err != nil {
		t.Fatalf("clean save: %v", err)
	}
	if _, err := s.LoadState(path); err != nil {
		t.Fatalf("load with no state file: %v", err)
	}

	report := &proto.TelemetryData{
		TopologyId:        "test-cluster-1",
		Version:           "4.40",
		Os:                "linux/amd64",
		VolumeServerCount: 5,
		TotalDiskBytes:    123 << 30,
		TotalVolumeCount:  42,
		FilerCount:        2,
		BrokerCount:       1,
		Timestamp:         time.Now().Unix(),
	}
	if err := s.StoreTelemetry(report); err != nil {
		t.Fatalf("store: %v", err)
	}
	receivedAt := s.instances[report.TopologyId].ReceivedAt

	if err := s.SaveStateIfDirty(path); err != nil {
		t.Fatalf("save: %v", err)
	}
	if s.dirty {
		t.Fatal("dirty flag not cleared after save")
	}

	// Simulate a restart: wipe the in-memory map, then restore.
	s.instances = make(map[string]*telemetryData)
	n, err := s.LoadState(path)
	if err != nil {
		t.Fatalf("load: %v", err)
	}
	if n != 1 {
		t.Fatalf("loaded %d instances, want 1", n)
	}

	got, ok := s.instances[report.TopologyId]
	if !ok {
		t.Fatal("instance missing after load")
	}
	if !got.ReceivedAt.Equal(receivedAt) {
		t.Errorf("ReceivedAt not preserved: got %v, want %v", got.ReceivedAt, receivedAt)
	}
	if got.TelemetryData.TotalDiskBytes != report.TotalDiskBytes ||
		got.TelemetryData.Version != report.Version ||
		got.TelemetryData.VolumeServerCount != report.VolumeServerCount {
		t.Errorf("fields not preserved: got %+v", got.TelemetryData)
	}

	// Load must not mark state dirty.
	if s.dirty {
		t.Error("dirty flag set after load")
	}
}

// State written before versions were recorded still knows the version of the
// report its newest sample came from: the instance record's.
func TestLoadStateFillsNewestSampleVersion(t *testing.T) {
	path := filepath.Join(t.TempDir(), "telemetry-state.json")

	s := newPrometheusStorage(prometheus.NewRegistry())
	report := &proto.TelemetryData{TopologyId: "test-cluster-1", Version: "4.40", Os: "linux/amd64", TotalDiskBytes: proto.MinDiskBytes}
	if err := s.StoreTelemetry(report); err != nil {
		t.Fatalf("store: %v", err)
	}
	yesterday := time.Now().AddDate(0, 0, -1).Unix()
	s.histories[report.TopologyId] = []HistorySample{
		{Ts: yesterday, TotalDiskBytes: 10},
		{Ts: time.Now().Unix(), TotalDiskBytes: 20},
	}
	if err := s.SaveStateIfDirty(path); err != nil {
		t.Fatalf("save: %v", err)
	}

	s = newPrometheusStorage(prometheus.NewRegistry())
	if _, err := s.LoadState(path); err != nil {
		t.Fatalf("load: %v", err)
	}
	loaded := s.histories[report.TopologyId]
	if len(loaded) != 2 {
		t.Fatalf("history = %+v, want 2 samples", loaded)
	}
	if loaded[1].Version != report.Version {
		t.Errorf("newest sample version = %q, want %q", loaded[1].Version, report.Version)
	}
	if loaded[0].Version != "" {
		t.Errorf("older sample version = %q, want it left unknown", loaded[0].Version)
	}
}
