package pgstore

import (
	"testing"
	"time"

	"textmachine/platform/internal/money"
)

// A1/money reproduction. SpendBound is documented as "the SMALLEST meter reading any LATER attempt
// of the same book recorded". The battery's only pin of it
// (runs.TestADeferredSettlementIsNotChargedForTheNextRunOfTheSameBook) puts exactly ONE later
// attempt in the book, where min and max are the same row — so the word `min` is not executed as a
// choice by anything. Mutation `min(` -> `max(` in Store.SpendBound passes ./internal/pgstore and
// ./internal/runs whole.
//
// This is what the choice costs when a book has TWO later attempts, which is the ordinary shape of a
// deferred settlement (run 1 defers, run 2 runs and ends, run 3 starts, run 1's retry lands): the
// bound must be run 2's baseline, and `max` makes it run 3's — which already contains run 2's spend,
// so the deferred settlement of run 1 pays for run 2's work and run 2 pays for it again. That is
// PD-124 one attempt further out.
func TestTheSpendBoundIsTheEARLIESTLaterReadingAndNotJustAnyOfThem(t *testing.T) {
	s, ctx := testDB(t)
	now := fundedAccount(t, s, ctx, "u1", "10")
	seedBook(t, s, ctx, "bk1", "u1", 500)
	// Three attempts of the same book. The first is the one whose settlement deferred; the second and
	// the third are what ran while it waited, and their baselines rise because the book's meter does.
	// live=false means the run has ended: one-live-run-per-book allows only the last one to be open.
	mk := func(runID string, attempt int, baseline int64, live bool) int64 {
		var ended any
		if !live {
			ended = now
		}
		exec(t, s, ctx, `insert into runs (id, book_id, status, verify_bank, ceiling_chapters, started_at,
		                                   finished_at, revision)
		                 values ($1,'bk1','ready',false,10,$2,$3,1)
		                 on conflict (id) do nothing`, runID, now, ended)
		var id int64
		if err := s.pool.QueryRow(ctx, `
			insert into run_attempts (run_id, attempt_no, started_at, last_offset, engine_run_id,
			                          spend_baseline_micro_usd)
			values ($1,$2::int,$3,0,$1||'#'||$2::int,$4) returning id`,
			runID, attempt, now, baseline).Scan(&id); err != nil {
			t.Fatal(err)
		}
		return id
	}
	first := mk("run_a", 1, 100_000, false)  // the deferred one: the book stood at $0.10 when it began
	_ = mk("run_b", 1, 200_000, false)       // ran next; the book stood at $0.20 when IT began
	_ = mk("run_c", 1, 500_000, true)       // ran after that; the book stood at $0.50 by then
	bound, err := s.SpendBound(ctx, "bk1", first)
	if err != nil {
		t.Fatal(err)
	}
	if bound == nil {
		t.Fatal("no bound at all: the fixture is not the one this test claims")
	}
	if want := money.MicroUSD(200_000); *bound != want {
		t.Fatalf("the bound is %s, want %s — the EARLIEST later reading is the only one taken after this attempt stopped and before the next one added anything; a later reading lets this settlement pay for its successor's work, which the successor then pays for again",
			bound.USD(), want.USD())
	}
	_ = time.Second
}
