package readmodel

// P8-REVIEW axis 3 probe. `readmodel.Drain` starts a book only while the pass has a WHOLE
// MaterializeBudget left (readmodel.go:183). The pass's budget is not in this package: it is
// `refreshSweepBudget` in cmd/tmplatformd/runner.go, a bare 10 * time.Minute with no reference to
// the constant it has to exceed. The two numbers are a PAIR, they live in two packages, and nothing
// asserts the relation between them.
//
// This shows what the wrong side of it does: a pass shorter than one book's budget materializes
// NOTHING, on every pass, for ever, and says nothing at all — no error, no log, no metric, and the
// debt column never moves.

import (
	"context"
	"testing"
	"time"

	"textmachine/platform/internal/ingest"
	"textmachine/platform/internal/pgstore"
)

type probeStore struct {
	owed   []pgstore.OwedBook
	claims int
}

func (p *probeStore) SaveStructure(context.Context, string, pgstore.Structure) error { return nil }
func (p *probeStore) SaveBank(context.Context, string, []ingest.BankTerm) error      { return nil }
func (p *probeStore) BooksOwedReadModel(_ context.Context, limit int) ([]pgstore.OwedBook, error) {
	return p.owed, nil
}
func (p *probeStore) ClaimReadModelDebt(_ context.Context, id string, owedAt time.Time, w time.Duration) (time.Time, error) {
	p.claims++
	return owedAt.Add(w), nil
}
func (p *probeStore) ClearReadModelDebt(context.Context, string, time.Time) error { return nil }
func (p *probeStore) DeferReadModelDebt(context.Context, string, time.Time, time.Time, string, pgstore.AttemptCost) (int, error) {
	return 0, nil
}
func (p *probeStore) AbandonReadModelDebt(context.Context, string, time.Time, time.Time, string) error {
	return nil
}

type probeEngine struct{ calls int }

func (e *probeEngine) Manifest(context.Context, string, string) (ingest.Manifest, error) {
	e.calls++
	return ingest.Manifest{ChaptersTotal: 1}, nil
}
func (e *probeEngine) Export(context.Context, string, string) (ingest.Export, error) {
	e.calls++
	return ingest.Export{}, nil
}

func TestProbeAPassShorterThanOneBookMaterialisesNothingAndSaysNothing(t *testing.T) {
	for _, tc := range []struct {
		name string
		pass time.Duration
	}{
		{"the shipped pass (cmd/tmplatformd refreshSweepBudget)", 10 * time.Minute},
		{"a pass one edit below one book's budget", MaterializeBudget - time.Second},
	} {
		t.Run(tc.name, func(t *testing.T) {
			store := &probeStore{owed: []pgstore.OwedBook{{ID: "bk_1", Workdir: "/tmp/x", OwedAt: time.Now()}}}
			eng := &probeEngine{}
			s := &Service{Store: store, Engine: eng, Binary: "/opt/tm/tmctl"}
			ctx, cancel := context.WithTimeout(t.Context(), tc.pass)
			defer cancel()
			if err := s.Drain(ctx); err != nil {
				t.Fatalf("Drain answered %v", err)
			}
			t.Logf("pass=%v: claims=%d engine calls=%d, Drain returned nil",
				tc.pass, store.claims, eng.calls)
		})
	}
}
