//go:build test && dev

package payments

import (
	"context"
	"testing"
	"time"

	"crussell/db"
	"crussell/testutils"
	"crussell/testutils/fixtures"
)

func setupRefundTestWithDiscount(t *testing.T, ctx context.Context, q db.Querier) (string, string, float64) {
	t.Helper()
	userID, err := fixtures.CreateTestUser(q)
	if err != nil {
		t.Fatalf("failed to create user: %v", err)
	}
	serviceID, err := fixtures.CreateTestService(q)
	if err != nil {
		t.Fatalf("failed to create service: %v", err)
	}
	bookingID, err := fixtures.CreateTestBookingAtTime(q, userID, serviceID, time.Date(2099, 12, 31, 10, 0, 0, 0, time.UTC))
	if err != nil {
		t.Fatalf("failed to create booking: %v", err)
	}

	// Insert a real cash payment of 50
	_, err = q.Exec(ctx, `
		INSERT INTO payments (booking_id, payment_type, payment_method, amount, status, created_at, updated_at)
		VALUES ($1, 'full', 'cash', 5000, 'completed', NOW(), NOW())
	`, bookingID)
	if err != nil {
		t.Fatalf("failed to create cash payment: %v", err)
	}

	// Insert a discount payment record (should be excluded from refund)
	_, err = q.Exec(ctx, `
		INSERT INTO payments (booking_id, payment_type, payment_method, amount, status, created_at, updated_at)
		VALUES ($1, 'partial', 'discount', 500, 'completed', NOW(), NOW())
	`, bookingID)
	if err != nil {
		t.Fatalf("failed to create discount payment: %v", err)
	}

	// Insert an on_the_house payment record (should also be excluded)
	_, err = q.Exec(ctx, `
		INSERT INTO payments (booking_id, payment_type, payment_method, amount, status, created_at, updated_at)
		VALUES ($1, 'partial', 'on_the_house', 1000, 'completed', NOW(), NOW())
	`, bookingID)
	if err != nil {
		t.Fatalf("failed to create on_the_house payment: %v", err)
	}

	return userID, bookingID, 50.0
}

func TestProcessCancellationRefund_ExcludesDiscountPayments(t *testing.T) {
	t.Parallel()
	ctx, tx := testutils.SetupTestTx(t)
	userID, bookingID, total := setupRefundTestWithDiscount(t, ctx, tx)

	farFuture := time.Date(2099, 12, 31, 10, 0, 0, 0, time.UTC)
	now := farFuture.Add(-72 * time.Hour).Add(-1 * time.Hour) // >72h before

	result, err := ProcessCancellationRefund(
		ctx, bookingID, total, 50,
		farFuture, now, "client_cancelled", &userID,
	)
	if err != nil {
		t.Fatalf("ProcessCancellationRefund failed: %v", err)
	}

	// Refundable should be 50 (only the cash payment), not 65 (which would include discount + OTH)
	if result.RefundableAmount != 50 {
		t.Errorf("expected refundable 50 (excluding discount/OTH), got %.2f", result.RefundableAmount)
	}
}

func TestProcessCancellationRefund_ExcludesOnTheHousePayments(t *testing.T) {
	t.Parallel()
	ctx, tx := testutils.SetupTestTx(t)
	userID, bookingID, total := setupRefundTestWithDiscount(t, ctx, tx)

	// Make on_the_house the only non-discount payment by marking the 50 cash as a payment that gets refunded
	// but also add a pure on_the_house booking with no real money
	_, err := tx.Exec(ctx, `
		INSERT INTO payments (booking_id, payment_type, payment_method, amount, status, created_at, updated_at)
		VALUES ($1, 'partial', 'discount', 2500, 'completed', NOW(), NOW())
	`, bookingID)
	if err != nil {
		t.Fatalf("failed to create extra discount: %v", err)
	}

	farFuture := time.Date(2099, 12, 31, 10, 0, 0, 0, time.UTC)
	now := farFuture.Add(-72 * time.Hour).Add(-1 * time.Hour)

	result, err := ProcessCancellationRefund(
		ctx, bookingID, total, 50,
		farFuture, now, "client_cancelled", &userID,
	)
	if err != nil {
		t.Fatalf("ProcessCancellationRefund failed: %v", err)
	}

	// Refundable should be based on the actual cash payment only
	if result.RefundableAmount != 50 {
		t.Errorf("expected refundable 50 (real money only), got %.2f", result.RefundableAmount)
	}
}
