package storage

import (
	"path/filepath"
	"testing"
)

func TestIntentStore_StatesAndPersistence(t *testing.T) {
	path := filepath.Join(t.TempDir(), "intent.json")
	s, err := OpenIntentStore(path)
	if err != nil {
		t.Fatalf("open: %v", err)
	}
	// new: absent → IntentNew
	if s.Get("uuid:A") != IntentNew {
		t.Fatalf("absent should be new, got %q", s.Get("uuid:A"))
	}
	if err := s.SetEnrolled("uuid:A"); err != nil {
		t.Fatal(err)
	}
	if err := s.SetEjected("uuid:B"); err != nil {
		t.Fatal(err)
	}
	if err := s.SetDecommissioned("uuid:C"); err != nil {
		t.Fatal(err)
	}
	// reload → states persisted
	s2, err := OpenIntentStore(path)
	if err != nil {
		t.Fatalf("reopen: %v", err)
	}
	if s2.Get("uuid:A") != IntentEnrolled || s2.Get("uuid:B") != IntentEjected || s2.Get("uuid:C") != IntentDecommissioned {
		t.Fatalf("states not persisted: A=%q B=%q C=%q", s2.Get("uuid:A"), s2.Get("uuid:B"), s2.Get("uuid:C"))
	}
}

func TestIntentStore_OnAbsent_ReplyRule(t *testing.T) {
	s, _ := OpenIntentStore(filepath.Join(t.TempDir(), "i.json"))
	_ = s.SetEjected("uuid:E")
	_ = s.SetDecommissioned("uuid:D")
	_ = s.SetEnrolled("uuid:N")

	// ejected → absent → enrolled (so a replug auto-mounts)
	if err := s.OnAbsent("uuid:E"); err != nil {
		t.Fatal(err)
	}
	if s.Get("uuid:E") != IntentEnrolled {
		t.Fatalf("ejected→absent should clear to enrolled, got %q", s.Get("uuid:E"))
	}
	// decommissioned survives absent
	_ = s.OnAbsent("uuid:D")
	if s.Get("uuid:D") != IntentDecommissioned {
		t.Fatalf("decommissioned must survive absent, got %q", s.Get("uuid:D"))
	}
	// enrolled unchanged by absent
	_ = s.OnAbsent("uuid:N")
	if s.Get("uuid:N") != IntentEnrolled {
		t.Fatalf("enrolled should stay enrolled, got %q", s.Get("uuid:N"))
	}
}

func TestIntentStore_EmptyDurableIDRefused(t *testing.T) {
	s, _ := OpenIntentStore(filepath.Join(t.TempDir(), "i.json"))
	if err := s.SetEnrolled(""); err == nil {
		t.Fatal("recording intent for an empty durable-id must be refused")
	}
	if s.Get("") != IntentNew {
		t.Fatal("empty durable-id must read as new")
	}
}

// ReconcilePermitted is the gate the reconciler uses: only an `enrolled` drive (intent-none) is
// auto-mounted; new/ejected/decommissioned are not. This documents the decision table.
func TestIntentStore_ReconcileGate(t *testing.T) {
	s, _ := OpenIntentStore(filepath.Join(t.TempDir(), "i.json"))
	_ = s.SetEnrolled("uuid:enr")
	_ = s.SetEjected("uuid:ej")
	_ = s.SetDecommissioned("uuid:dec")
	cases := map[string]bool{
		"uuid:enr": true,  // enrolled → reconcile
		"uuid:ej":  false, // ejected → leave alone
		"uuid:dec": false, // decommissioned → never
		"uuid:new": false, // new → never auto-mount
	}
	for id, want := range cases {
		got := s.Get(id) == IntentEnrolled
		if got != want {
			t.Errorf("reconcile-permitted(%s): got %v want %v (intent %q)", id, got, want, s.Get(id))
		}
	}
}
