package stats

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

	"reasonix/internal/usagecatalog"
)

func TestUsageManagerCloseFencesOpenAndAllowsRestart(t *testing.T) {
	manager := &usageManager{}
	started := make(chan struct{})
	release := make(chan struct{})
	databasePath := filepath.Join(t.TempDir(), "usage.sqlite")
	manager.open = func(ctx context.Context, path string) (*usagecatalog.Catalog, error) {
		close(started)
		<-release
		return usagecatalog.Open(ctx, databasePath)
	}
	dir := t.TempDir()
	manager.start(dir)
	<-started

	closed := make(chan error, 1)
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	go func() { closed <- manager.close(ctx) }()
	select {
	case err := <-closed:
		t.Fatalf("close returned before in-flight open exited: %v", err)
	default:
	}
	close(release)
	if err := <-closed; err != nil {
		t.Fatalf("close after open fence: %v", err)
	}
	if catalog := manager.catalog.Load(); catalog != nil {
		t.Fatal("stale open published a usage catalog after close")
	}

	manager.mu.Lock()
	manager.open = func(ctx context.Context, path string) (*usagecatalog.Catalog, error) {
		return usagecatalog.Open(ctx, databasePath)
	}
	manager.mu.Unlock()
	manager.start(dir)
	manager.mu.Lock()
	reopened := manager.openDone
	manager.mu.Unlock()
	if reopened == nil {
		t.Fatal("manager did not start a new generation after close")
	}
	<-reopened
	if catalog := manager.catalog.Load(); catalog == nil {
		t.Fatal("manager did not publish the restarted usage catalog")
	}
	if err := manager.close(ctx); err != nil {
		t.Fatalf("close restarted usage catalog: %v", err)
	}
}
