package localapi

import (
	"os"
	"path/filepath"
	"strings"
	"testing"
)

func TestTokenStore_MintLookup(t *testing.T) {
	path := filepath.Join(t.TempDir(), "tokens.log")
	s, err := OpenTokenStore(path)
	if err != nil {
		t.Fatalf("open: %v", err)
	}
	defer s.Close()

	tok, err := s.Mint(8200)
	if err != nil {
		t.Fatalf("mint: %v", err)
	}
	if tok == "" {
		t.Fatal("mint returned empty token")
	}
	if vmid, ok := s.Lookup(tok); !ok || vmid != 8200 {
		t.Fatalf("lookup: got (%d,%v), want (8200,true)", vmid, ok)
	}
	if _, ok := s.Lookup("not-a-real-token"); ok {
		t.Fatal("lookup of unknown token succeeded")
	}
	if _, ok := s.Lookup(""); ok {
		t.Fatal("lookup of empty token succeeded")
	}
}

// The persisted file must contain only the HASH, never the plaintext token.
func TestTokenStore_PlaintextNeverPersisted(t *testing.T) {
	path := filepath.Join(t.TempDir(), "tokens.log")
	s, err := OpenTokenStore(path)
	if err != nil {
		t.Fatalf("open: %v", err)
	}
	tok, err := s.Mint(101)
	if err != nil {
		t.Fatalf("mint: %v", err)
	}
	s.Close()

	b, err := os.ReadFile(path)
	if err != nil {
		t.Fatalf("read store: %v", err)
	}
	if strings.Contains(string(b), tok) {
		t.Fatal("plaintext token found in the persisted store — must store only the hash")
	}
	if !strings.Contains(string(b), hashToken(tok)) {
		t.Fatal("token hash not found in the persisted store")
	}
}

// A re-mint for the same guest revokes the previous token (last-write-wins).
func TestTokenStore_RemintRevokesOld(t *testing.T) {
	path := filepath.Join(t.TempDir(), "tokens.log")
	s, err := OpenTokenStore(path)
	if err != nil {
		t.Fatalf("open: %v", err)
	}
	defer s.Close()

	old, _ := s.Mint(7)
	fresh, _ := s.Mint(7)
	if old == fresh {
		t.Fatal("re-mint produced the same token")
	}
	if _, ok := s.Lookup(old); ok {
		t.Fatal("old token still valid after re-mint")
	}
	if vmid, ok := s.Lookup(fresh); !ok || vmid != 7 {
		t.Fatalf("fresh token lookup: got (%d,%v), want (7,true)", vmid, ok)
	}
}

// Durability: tokens survive a store reopen (replay).
func TestTokenStore_SurvivesReopen(t *testing.T) {
	path := filepath.Join(t.TempDir(), "tokens.log")
	s1, err := OpenTokenStore(path)
	if err != nil {
		t.Fatalf("open: %v", err)
	}
	a, _ := s1.Mint(1)
	b, _ := s1.Mint(2)
	// rotate guest 1
	a2, _ := s1.Mint(1)
	s1.Close()

	s2, err := OpenTokenStore(path)
	if err != nil {
		t.Fatalf("reopen: %v", err)
	}
	defer s2.Close()

	if _, ok := s2.Lookup(a); ok {
		t.Fatal("rotated-out token survived reopen")
	}
	if vmid, ok := s2.Lookup(a2); !ok || vmid != 1 {
		t.Fatalf("guest1 current token lost across reopen: (%d,%v)", vmid, ok)
	}
	if vmid, ok := s2.Lookup(b); !ok || vmid != 2 {
		t.Fatalf("guest2 token lost across reopen: (%d,%v)", vmid, ok)
	}
}

func TestTokenStore_Uniqueness(t *testing.T) {
	path := filepath.Join(t.TempDir(), "tokens.log")
	s, err := OpenTokenStore(path)
	if err != nil {
		t.Fatalf("open: %v", err)
	}
	defer s.Close()
	seen := map[string]bool{}
	for i := 1; i <= 200; i++ {
		tok, err := s.Mint(i)
		if err != nil {
			t.Fatalf("mint %d: %v", i, err)
		}
		if seen[tok] {
			t.Fatalf("duplicate token at %d", i)
		}
		seen[tok] = true
	}
}
