//go:build integration

package inttest

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

	"scrabble/backend/internal/payments"
)

// TestConsoleRefundAndExport drives the manual refund and the ledger CSV export: a funded order is
// refunded in full (chips revoked, a refund row), the refund is idempotent, and the export carries
// the fund + refund rows; the refund POST is CSRF-guarded.
func TestConsoleRefundAndExport(t *testing.T) {
	ctx := context.Background()
	srv, _, pay := bannerServer(t)
	h := srv.Handler()
	id := provisionAccount(t)
	const origin = "http://admin.test"
	base := "http://admin.test/_gm/users/" + id.String()

	// Fund a pack: 100 chips + a fund ledger row.
	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("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)
	}

	// CSRF: a refund without the origin header is refused.
	if code, _ := consoleDo(h, http.MethodPost, base+"/refund", "order_id="+res.OrderID.String(), ""); code != http.StatusForbidden {
		t.Fatalf("refund without origin = %d, want 403", code)
	}

	// Refund the order in full → 100 chips revoked (none spent).
	if code, body := consoleDo(h, http.MethodPost, base+"/refund", "order_id="+res.OrderID.String(), origin); code != http.StatusOK || !strings.Contains(body, "revoked 100 chips") {
		t.Fatalf("refund = %d, has 'revoked 100 chips' = %v", code, strings.Contains(body, "revoked 100 chips"))
	}
	stmt, err := pay.AccountStatement(ctx, id)
	if err != nil {
		t.Fatalf("statement: %v", err)
	}
	for _, sg := range stmt.Segments {
		if sg.Source == payments.SourceDirect && sg.Chips != 0 {
			t.Errorf("after refund: direct chips = %d, want 0", sg.Chips)
		}
	}
	kinds := map[string]int{}
	for _, e := range stmt.Ledger {
		kinds[e.Kind]++
	}
	if kinds["fund"] != 1 || kinds["refund"] != 1 {
		t.Errorf("ledger kinds = %v, want one fund + one refund", kinds)
	}

	// A second refund of the same order is idempotent.
	if code, body := consoleDo(h, http.MethodPost, base+"/refund", "order_id="+res.OrderID.String(), origin); code != http.StatusOK || !strings.Contains(body, "Already refunded") {
		t.Fatalf("second refund = %d, has 'Already refunded' = %v", code, strings.Contains(body, "Already refunded"))
	}

	// Export the whole ledger as CSV: the header, this account, and its fund + refund rows.
	code, body := consoleDo(h, http.MethodGet, "http://admin.test/_gm/ledger.csv", "", "")
	if code != http.StatusOK {
		t.Fatalf("export = %d, want 200", code)
	}
	for _, want := range []string{"created_at,account_id,kind", id.String(), ",fund,", ",refund,"} {
		if !strings.Contains(body, want) {
			t.Errorf("ledger CSV missing %q", want)
		}
	}
}
