package account

import (
	"testing"
	"time"

	"github.com/google/uuid"
)

// TestSuspensionActiveAt covers the wall-clock re-evaluation the cache relies on: a permanent
// block is always active, a future-dated one is active, a past-dated one is not.
func TestSuspensionActiveAt(t *testing.T) {
	now := time.Date(2026, 6, 14, 12, 0, 0, 0, time.UTC)
	future := now.Add(time.Hour)
	past := now.Add(-time.Hour)

	if !suspensionActiveAt(Suspension{BlockedUntil: nil}, now) {
		t.Error("a permanent block must be active")
	}
	if !suspensionActiveAt(Suspension{BlockedUntil: &future}, now) {
		t.Error("a future-dated block must be active")
	}
	if suspensionActiveAt(Suspension{BlockedUntil: &past}, now) {
		t.Error("a past-dated block must be inactive")
	}
}

// TestSuspensionCache covers the cache primitives: a miss on an empty cache, a hit after put for
// both the not-blocked and blocked markers, and a miss after invalidate.
func TestSuspensionCache(t *testing.T) {
	c := newSuspensionCache()
	id := uuid.New()

	if _, ok := c.get(id); ok {
		t.Fatal("empty cache must miss")
	}

	c.put(id, suspensionCacheEntry{found: false})
	if e, ok := c.get(id); !ok || e.found {
		t.Fatalf("cached not-blocked entry = (%+v, ok %v), want hit with found=false", e, ok)
	}

	c.put(id, suspensionCacheEntry{susp: Suspension{AccountID: id}, found: true})
	if e, ok := c.get(id); !ok || !e.found {
		t.Fatalf("cached blocked entry = (%+v, ok %v), want hit with found=true", e, ok)
	}

	c.invalidate(id)
	if _, ok := c.get(id); ok {
		t.Fatal("invalidated entry must miss")
	}
}
