package web

import (
	"testing"
	"time"

	"gitea.dooplex.hu/admin/felhom-controller/internal/settings"
)

// TestOffboxCeremonyWaitState — truth table for the post-ceremony escrow card pick (v0.138.0).
// The awaiting card bridges the report-cycle gap between a completed ceremony and the hub-verified
// pending→escrowed flip; it must degrade to a warning after the grace window and must NEVER show
// once escrowed, unstamped, or on an unparseable stamp (those fall back to the plain pending CTA).
//
// COMPANION red-proof (run → fail → revert, recorded in REPORT): change the escrowed guard so it
// no longer short-circuits (e.g. drop `t.EscrowState == "escrowed"` from the early return) → the
// "escrowed clears the wait" case below FAILS (it would report awaiting on an already-confirmed
// target, resurfacing the interim card after the healthy state). Alternatively flip `>=` to `>` at
// the boundary and the exact-boundary case FAILS.
func TestOffboxCeremonyWaitState(t *testing.T) {
	now := time.Now()
	within := now.Add(-10 * time.Minute).Format(time.RFC3339)            // inside the 35m grace window
	past := now.Add(-40 * time.Minute).Format(time.RFC3339)              // past the grace window
	boundary := now.Add(-escrowCeremonyGraceWindow).Format(time.RFC3339) // exactly at the window → timed out (>=)

	cases := []struct {
		name         string
		target       *settings.OffboxTarget
		wantAwaiting bool
		wantTimedOut bool
	}{
		{"nil target", nil, false, false},
		{"pending, no stamp (plain CTA)", &settings.OffboxTarget{EscrowState: "pending"}, false, false},
		{"pending, stamped within window → awaiting", &settings.OffboxTarget{EscrowState: "pending", CeremonyCompletedAt: within}, true, false},
		{"pending, stamped past window → timed out", &settings.OffboxTarget{EscrowState: "pending", CeremonyCompletedAt: past}, false, true},
		{"pending, stamped at boundary → timed out", &settings.OffboxTarget{EscrowState: "pending", CeremonyCompletedAt: boundary}, false, true},
		{"escrowed clears the wait (stamp ignored)", &settings.OffboxTarget{EscrowState: "escrowed", CeremonyCompletedAt: within}, false, false},
		{"empty state, stamped within window → awaiting", &settings.OffboxTarget{EscrowState: "", CeremonyCompletedAt: within}, true, false},
		{"pending, unparseable stamp → plain CTA", &settings.OffboxTarget{EscrowState: "pending", CeremonyCompletedAt: "not-a-timestamp"}, false, false},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			gotAwaiting, gotTimedOut := offboxCeremonyWaitState(c.target)
			if gotAwaiting != c.wantAwaiting || gotTimedOut != c.wantTimedOut {
				t.Errorf("offboxCeremonyWaitState() = (awaiting=%v, timedOut=%v), want (awaiting=%v, timedOut=%v)",
					gotAwaiting, gotTimedOut, c.wantAwaiting, c.wantTimedOut)
			}
			// Mutual exclusion invariant — the two card branches must never both fire.
			if gotAwaiting && gotTimedOut {
				t.Errorf("%s: both awaiting and timedOut true — the card branches are not mutually exclusive", c.name)
			}
		})
	}
}
