//go:build integration

package inttest

import (
	"context"
	"net/http"
	"strings"
	"testing"

	"github.com/google/uuid"

	"scrabble/backend/internal/payments"
)

// TestAccountStatement checks the admin financial statement: a funded pack shows as a chip segment
// + a fund ledger row, an admin grant as a benefit + an admin_grant row, the ledger is newest-first,
// and a clean account carries no refund risk.
func TestAccountStatement(t *testing.T) {
	ctx := context.Background()
	svc := newPaymentsService()
	acc := uuid.New()

	// A funded pack: 100 chips to the direct segment + a fund ledger row.
	prod := seedPackProduct(t, 100, methodPrice{method: "direct", currency: "RUB", amount: 14900})
	res, err := svc.CreateOrder(ctx, acc, payments.NewContext("direct", "web"), []payments.Source{payments.SourceDirect}, prod, "robokassa")
	if err != nil {
		t.Fatalf("create order: %v", err)
	}
	paid, _ := payments.MoneyFromMinor(14900, payments.CurrencyRUB)
	if _, err := svc.Fund(ctx, res.OrderID, "robokassa", res.OrderID.String(), paid); err != nil {
		t.Fatalf("fund: %v", err)
	}
	// An admin grant: 5 hints to the direct origin + an admin_grant ledger row.
	if err := svc.Grant(ctx, acc, payments.SourceDirect, 5, 0, false); err != nil {
		t.Fatalf("grant: %v", err)
	}

	stmt, err := svc.AccountStatement(ctx, acc)
	if err != nil {
		t.Fatalf("statement: %v", err)
	}

	if len(stmt.Segments) != 1 || stmt.Segments[0].Source != payments.SourceDirect || stmt.Segments[0].Chips != 100 {
		t.Fatalf("segments = %+v, want 100 chips on direct", stmt.Segments)
	}
	if len(stmt.Benefits) != 1 || stmt.Benefits[0].Origin != payments.SourceDirect || stmt.Benefits[0].Hints != 5 {
		t.Fatalf("benefits = %+v, want 5 hints on direct", stmt.Benefits)
	}
	if len(stmt.Ledger) != 2 {
		t.Fatalf("ledger rows = %d, want 2 (fund + admin_grant)", len(stmt.Ledger))
	}
	// Newest-first ordering (the grant is the later write).
	if stmt.Ledger[0].CreatedAt.Before(stmt.Ledger[1].CreatedAt) {
		t.Error("ledger is not newest-first")
	}
	kinds := map[string]int{}
	for _, e := range stmt.Ledger {
		kinds[e.Kind]++
		if e.Kind == "fund" && e.ChipsDelta != 100 {
			t.Errorf("fund chips delta = %d, want 100", e.ChipsDelta)
		}
	}
	if kinds["fund"] != 1 || kinds["admin_grant"] != 1 {
		t.Fatalf("ledger kinds = %v, want one fund + one admin_grant", kinds)
	}
	if stmt.Risk.Present {
		t.Errorf("risk = %+v, want none for a clean account", stmt.Risk)
	}
}

// TestConsoleFinancePanel checks the user card renders the finance panel: a funded pack + an admin
// grant surface as the segment balance, the benefit and the lifetime summary. The operations
// themselves belong to the ledger section, which the card links to scoped to this account.
func TestConsoleFinancePanel(t *testing.T) {
	ctx := context.Background()
	srv, _, pay := bannerServer(t)
	id := provisionAccount(t)

	prod := seedPackProduct(t, 100, methodPrice{method: "direct", currency: "RUB", amount: 14900})
	res, err := pay.CreateOrder(ctx, id, payments.NewContext("direct", "web"), []payments.Source{payments.SourceDirect}, prod, "robokassa")
	if err != nil {
		t.Fatalf("create order: %v", err)
	}
	paid, _ := payments.MoneyFromMinor(14900, payments.CurrencyRUB)
	if _, err := pay.Fund(ctx, res.OrderID, "robokassa", res.OrderID.String(), paid); err != nil {
		t.Fatalf("fund: %v", err)
	}
	if err := pay.Grant(ctx, id, payments.SourceDirect, 5, 0, false); err != nil {
		t.Fatalf("grant: %v", err)
	}

	code, body := consoleDo(srv.Handler(), http.MethodGet, "http://admin.test/_gm/users/"+id.String(), "", "")
	if code != http.StatusOK {
		t.Fatalf("user card = %d, want 200", code)
	}
	for _, want := range []string{
		"Finance", "Chips (direct)", "Benefits (direct)", "5 hints",
		"Chips credited", "149.00 RUB", // the lifetime summary: chips in, money paid
		"/_gm/ledger?user=" + id.String(), // the hand-off to the operations view
	} {
		if !strings.Contains(body, want) {
			t.Errorf("finance panel missing %q", want)
		}
	}
	// The card must not re-render the operations the ledger section owns.
	if strings.Contains(body, "admin_grant") {
		t.Error("the user card still lists ledger rows; they belong to /_gm/ledger now")
	}
}
