package commerce

import (
	"testing"
	"time"
)

func TestDiscountAmount(t *testing.T) {
	tests := []struct {
		name     string
		coupon   PromoCode
		eligible int
		want     int
	}{
		{name: "percent", coupon: PromoCode{Type: "percent", Value: 30}, eligible: 10000, want: 3000},
		{name: "percent cap", coupon: PromoCode{Type: "percent", Value: 50, MaxDiscountAmount: 1200}, eligible: 10000, want: 1200},
		{name: "fixed", coupon: PromoCode{Type: "fixed", Value: 1500}, eligible: 1000, want: 1000},
		{name: "threshold met", coupon: PromoCode{Type: "threshold_fixed", Value: 1000, MinOrderAmount: 5000}, eligible: 6000, want: 1000},
		{name: "threshold missed", coupon: PromoCode{Type: "threshold_fixed", Value: 1000, MinOrderAmount: 5000}, eligible: 4000, want: 0},
		{name: "override", coupon: PromoCode{Type: "override", Value: 2500}, eligible: 6000, want: 3500},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := discountAmount(tt.coupon, tt.eligible); got != tt.want {
				t.Fatalf("discountAmount() = %d, want %d", got, tt.want)
			}
		})
	}
}

func TestOrderItemDiscounts(t *testing.T) {
	got := orderItemDiscounts(map[int64]int{10: 1000, 20: 2000, 30: 3000}, 1000)
	want := map[int64]int{10: 167, 20: 333, 30: 500}
	for id, amount := range want {
		if got[id] != amount {
			t.Fatalf("item %d discount = %d, want %d; all=%v", id, got[id], amount, got)
		}
	}
}

func TestCalculatePointsDiscount(t *testing.T) {
	points, cents := calculatePointsDiscount(9000, 10000, 3500)
	if points != 9000 || cents != 900 {
		t.Fatalf("calculatePointsDiscount() = (%d, %d), want (9000, 900)", points, cents)
	}
}

func TestSplitAmount(t *testing.T) {
	got := splitAmount(1000, 3)
	want := []int{334, 333, 333}
	if len(got) != len(want) {
		t.Fatalf("split len = %d, want %d", len(got), len(want))
	}
	for idx := range want {
		if got[idx] != want[idx] {
			t.Fatalf("split[%d] = %d, want %d; all=%v", idx, got[idx], want[idx], got)
		}
	}
}

func TestAllocateFinalAmounts(t *testing.T) {
	got := allocateFinalAmounts([]int{800, 400, 400}, 1300, 1600)
	want := []int{650, 325, 325}
	for idx := range want {
		if got[idx] != want[idx] {
			t.Fatalf("allocated[%d] = %d, want %d; all=%v", idx, got[idx], want[idx], got)
		}
	}
}

func TestSelfPurchaseReward(t *testing.T) {
	points, cents := selfPurchaseReward(12345, 500)
	if points != 6170 || cents != 617 {
		t.Fatalf("reward = (%d, %d), want (6170, 617)", points, cents)
	}
}

func TestAgentSettlementSnapshotProfit(t *testing.T) {
	got := agentSettlementSnapshot(10000, 9000, 7000)
	if got.settlementType != "agent_profit" || got.costAmount != 7000 || got.deltaAmount != 2000 || got.pointsAmount != 20000 {
		t.Fatalf("unexpected settlement snapshot: %#v", got)
	}
}

func TestAgentSettlementSnapshotSubsidy(t *testing.T) {
	got := agentSettlementSnapshot(10000, 6000, 7000)
	if got.settlementType != "agent_subsidy" || got.costAmount != 7000 || got.deltaAmount != -1000 || got.pointsAmount != 0 {
		t.Fatalf("unexpected settlement snapshot: %#v", got)
	}
}

func TestSettlementReleaseAt(t *testing.T) {
	created := time.Date(2026, 7, 9, 10, 0, 0, 0, time.UTC)
	got := settlementReleaseAt(created, 3)
	if !got.Equal(created.AddDate(0, 0, 3)) {
		t.Fatalf("release_at = %s, want +3 days", got)
	}
}

func TestSettingInt(t *testing.T) {
	if got := settingInt(JSONRaw(`"5"`), 3); got != 5 {
		t.Fatalf("settingInt string = %d, want 5", got)
	}
	if got := settingInt(JSONRaw(`bad`), 3); got != 3 {
		t.Fatalf("settingInt bad = %d, want default", got)
	}
}

func TestNotificationSenderName(t *testing.T) {
	if got := notificationSenderName("promotion"); got != "推广中心" {
		t.Fatalf("promotion sender = %q", got)
	}
	if got := notificationSenderName("unknown"); got != "系统通知" {
		t.Fatalf("fallback sender = %q", got)
	}
}

func TestParseIntSet(t *testing.T) {
	raw := `["1", 2, " 3 "]`
	got := parseIntSet(&raw)
	for _, id := range []int64{1, 2, 3} {
		if !got[id] {
			t.Fatalf("parseIntSet() missing %d: %v", id, got)
		}
	}
}

func TestParseMemoryMB(t *testing.T) {
	raw := "4GB"
	got := parseMemoryMB(&raw)
	if got == nil || *got != 4096 {
		t.Fatalf("parseMemoryMB() = %v, want 4096", got)
	}
}

func TestBuildItemsSnapshotIncludesCouponDiscount(t *testing.T) {
	memory := "2G"
	checkout := checkoutContext{
		cartItems: []CartItem{{
			ID:        10,
			ProductID: 20,
			Cycle:     "monthly",
			Quantity:  1,
			UnitPrice: 9.9,
		}},
		products: map[int64]Product{
			20: {ID: 20, SKU: "sku", Name: "VPS", Status: "active", Memory: &memory},
		},
		itemTotals: map[int64]int{10: 990},
		total:      990,
	}
	application := &couponApplication{
		coupon:        PromoCode{Code: "SAVE", DiscountLevel: "order"},
		itemDiscounts: map[int64]int{10: 190},
	}

	snapshots := buildItemsSnapshot(checkout, application)
	if len(snapshots) != 1 {
		t.Fatalf("snapshot len = %d, want 1", len(snapshots))
	}
	if snapshots[0]["coupon_discount_cents"] != 190 {
		t.Fatalf("coupon_discount_cents = %v, want 190", snapshots[0]["coupon_discount_cents"])
	}
	if snapshots[0]["payable_before_points_cents"] != 800 {
		t.Fatalf("payable_before_points_cents = %v, want 800", snapshots[0]["payable_before_points_cents"])
	}
	if snapshots[0]["product_memory_mb"] == nil {
		t.Fatal("expected product_memory_mb")
	}
}

func TestNewOrderDetailResponse(t *testing.T) {
	now := time.Date(2026, 7, 9, 10, 0, 0, 0, time.UTC)
	ip := "203.0.113.10"
	hostname := "vm-1"
	order := Order{
		ID:             1,
		OutOrderNo:     "ORD1",
		Status:         "paid",
		TotalAmount:    1000,
		DiscountAmount: 100,
		ItemsSnapshot:  JSONRaw(`[{"product_name":"VPS","item_total_cents":1000}]`),
		CreatedAt:      now,
	}
	got := newOrderDetailResponse(order, []Instance{{
		ID:        2,
		Status:    "provisioning",
		MainIP:    &ip,
		Hostname:  &hostname,
		ExpiresAt: &now,
	}})

	if got.ID != 1 || got.OutOrderNo != "ORD1" || len(got.ItemsSnapshot) != 1 || len(got.Instances) != 1 {
		t.Fatalf("unexpected order detail: %#v", got)
	}
	if got.Instances[0].MainIP == nil || *got.Instances[0].MainIP != ip {
		t.Fatalf("unexpected instance response: %#v", got.Instances[0])
	}
}
