package web

// v0.67.0 (R-36 sub-item) — the self-bind link is minted automatically at customer creation and at
// RESET completion, so the box's console banner („nyisd meg az e-mailben kapott link") is already
// true when the customer first reads it, instead of true-once-the-operator-remembers.
//
// The load-bearing property is that auto-minting NEVER fails the operation it rides on: a customer
// create that provisioned Cloudflare, offsite and PBS must not 500 because a courtesy email
// bounced.

import (
	"testing"

	"gitea.dooplex.hu/admin/felhom-hub/internal/store"
)

func seedForMint(t *testing.T, st *store.Store, id, email string) {
	t.Helper()
	if err := st.SaveCustomerConfig(&store.CustomerConfig{
		CustomerID: id, CustomerName: id, Domain: id + ".hu",
		RetrievalPassword: "pw", APIKey: "k", Status: "active", Email: email,
	}); err != nil {
		t.Fatal(err)
	}
}

func liveTokenCount(t *testing.T, st *store.Store, customerID string) int {
	t.Helper()
	n, err := st.CountSelfBindTokens(customerID)
	if err != nil {
		t.Fatalf("count self-bind tokens: %v", err)
	}
	return n
}

func TestAutoMintSelfBindLink(t *testing.T) {
	t.Run("mints and sends when an email is registered", func(t *testing.T) {
		s, st := newTestServer(t)
		m := &stubMailer{}
		s.SetSelfBindMailer(m)
		seedForMint(t, st, "acme", "ops@acme.hu")

		s.autoMintSelfBindLink("acme", "ops@acme.hu", "customer creation")

		if m.link == "" {
			t.Fatal("no self-bind link was sent")
		}
		if liveTokenCount(t, st, "acme") != 1 {
			t.Error("expected exactly one live capability token after auto-mint")
		}
	})

	t.Run("no registered email → nothing minted (F1 honoured)", func(t *testing.T) {
		s, st := newTestServer(t)
		m := &stubMailer{}
		s.SetSelfBindMailer(m)
		seedForMint(t, st, "acme", "")

		s.autoMintSelfBindLink("acme", "", "customer creation")

		if m.link != "" {
			t.Error("a link was sent for a customer with no registered address")
		}
		if liveTokenCount(t, st, "acme") != 0 {
			t.Error("a token was minted that nobody could ever receive — F1 says mint nothing")
		}
	})

	t.Run("send failure invalidates the token (F2 honoured)", func(t *testing.T) {
		s, st := newTestServer(t)
		s.SetSelfBindMailer(&stubMailer{fail: true})
		seedForMint(t, st, "acme", "ops@acme.hu")

		s.autoMintSelfBindLink("acme", "ops@acme.hu", "customer creation")

		if liveTokenCount(t, st, "acme") != 0 {
			t.Error("send failed but a live capability token was left behind — F2 says delete it")
		}
	})

	t.Run("RESET does not leave a pre-RESET link live", func(t *testing.T) {
		// PurgeCustomerResetDBState does NOT clear selfbind_tokens, so a link minted before a reset
		// would otherwise survive it. Auto-mint must guarantee that afterwards the only live token
		// is one it just issued — or none.
		s, st := newTestServer(t)
		s.SetSelfBindMailer(&stubMailer{})
		seedForMint(t, st, "acme", "ops@acme.hu")

		// A link exists from before the reset.
		s.autoMintSelfBindLink("acme", "ops@acme.hu", "customer creation")
		if liveTokenCount(t, st, "acme") != 1 {
			t.Fatal("setup: expected a pre-reset token")
		}

		// Now the customer loses their address and a RESET happens: the skip path must still clear it.
		s.autoMintSelfBindLink("acme", "", "RESET completion")
		if liveTokenCount(t, st, "acme") != 0 {
			t.Error("a capability link minted BEFORE the reset is still live after it")
		}
	})

	t.Run("no mailer configured → no token, no panic", func(t *testing.T) {
		s, st := newTestServer(t) // SetSelfBindMailer never called
		seedForMint(t, st, "acme", "ops@acme.hu")

		s.autoMintSelfBindLink("acme", "ops@acme.hu", "customer creation")

		if liveTokenCount(t, st, "acme") != 0 {
			t.Error("a token was minted with no mailer to deliver it")
		}
	})
}
