package databi

import (
	"context"
	"testing"
	"time"

	luckygiftv1 "hyapp.local/api/proto/luckygift/v1"
)

type fakeLuckyGiftDailyStatsSource struct {
	lastReq *luckygiftv1.ListLuckyGiftDailyStatsRequest
	stats   []*luckygiftv1.LuckyGiftDailyStat
}

func (f *fakeLuckyGiftDailyStatsSource) ListLuckyGiftDailyStats(_ context.Context, req *luckygiftv1.ListLuckyGiftDailyStatsRequest) (*luckygiftv1.ListLuckyGiftDailyStatsResponse, error) {
	f.lastReq = req
	return &luckygiftv1.ListLuckyGiftDailyStatsResponse{Stats: f.stats}, nil
}

func TestRequirementsLuckyGiftV3Gating(t *testing.T) {
	for _, tc := range []struct {
		section  string
		includes bool
		only     bool
	}{
		{"", true, false},
		{"all", true, false},
		{"lucky_gift_v3", true, true},
		{" Lucky_Gift_V3 ", true, true},
		{"revenue", false, false},
		{"game", false, false},
	} {
		if got := requirementsIncludesLuckyGiftV3(tc.section); got != tc.includes {
			t.Fatalf("includes(%q)=%v, want %v", tc.section, got, tc.includes)
		}
		if got := requirementsOnlyLuckyGiftV3(tc.section); got != tc.only {
			t.Fatalf("only(%q)=%v, want %v", tc.section, got, tc.only)
		}
	}
}

// 回归：section 组装——按北京日零填充整个窗口、比例按合计重算、v3 策略与区域过滤透传到 RPC。
func TestLuckyGiftV3Section(t *testing.T) {
	source := &fakeLuckyGiftDailyStatsSource{stats: []*luckygiftv1.LuckyGiftDailyStat{
		{StatDay: "2026-07-11", DrawCount: 4, TurnoverCoin: 8_000, PayoutCoin: 6_000, BaseRewardCoin: 5_500},
	}}
	service := &Service{luckyGiftStats: source, luckyGiftTimeout: time.Second}

	// 北京 2026-07-10 00:00 ~ 2026-07-12 00:00（排他）= 两个北京日。
	startMS := time.Date(2026, 7, 9, 16, 0, 0, 0, time.UTC).UnixMilli()
	endMS := time.Date(2026, 7, 11, 16, 0, 0, 0, time.UTC).UnixMilli()
	section, err := service.luckyGiftV3Section(context.Background(), "lalu", RequirementsQuery{StartMS: startMS, EndMS: endMS}, []int64{7, 8})
	if err != nil {
		t.Fatalf("build section: %v", err)
	}

	if source.lastReq.GetStrategyVersion() != "dynamic_v3" || source.lastReq.GetMeta().GetAppCode() != "lalu" {
		t.Fatalf("rpc request mismatch: %+v", source.lastReq)
	}
	if regions := source.lastReq.GetRegionIds(); len(regions) != 2 || regions[0] != 7 || regions[1] != 8 {
		t.Fatalf("rpc region ids mismatch: %v", regions)
	}
	if section["key"] != luckyGiftV3SectionKey {
		t.Fatalf("section key mismatch: %v", section["key"])
	}

	rows, ok := section["daily_series"].([]map[string]any)
	if !ok || len(rows) != 2 {
		t.Fatalf("daily_series rows=%v, want 2 zero-filled days", section["daily_series"])
	}
	if rows[0]["stat_day"] != "2026-07-10" || rows[0]["draw_count"] != float64(0) {
		t.Fatalf("zero-filled day mismatch: %+v", rows[0])
	}
	if rows[0]["payout_rate"] != nil {
		t.Fatalf("zero turnover day must render nil ratio, got %v", rows[0]["payout_rate"])
	}
	if rows[1]["stat_day"] != "2026-07-11" || rows[1]["turnover_coin"] != float64(8_000) || rows[1]["profit_coin"] != float64(2_000) {
		t.Fatalf("data day mismatch: %+v", rows[1])
	}
	if rate := rows[1]["payout_rate"].(float64); rate != 0.75 {
		t.Fatalf("payout_rate=%v, want 0.75", rate)
	}

	total, ok := section["total"].(map[string]any)
	if !ok || total["draw_count"] != float64(4) || total["profit_coin"] != float64(2_000) {
		t.Fatalf("total mismatch: %+v", total)
	}
	average, ok := section["average"].(map[string]any)
	if !ok || average["draw_count"] != float64(2) || average["turnover_coin"] != float64(4_000) {
		t.Fatalf("average mismatch: %+v", average)
	}
	// 平均值行的比例 = 合计比例（4000/… 与 6000/8000 相同），不是逐日比例算术平均。
	if rate := average["payout_rate"].(float64); rate != 0.75 {
		t.Fatalf("average payout_rate=%v, want 0.75", rate)
	}
}

func TestLuckyGiftV3StatDaysCrossesBeijingMidnight(t *testing.T) {
	// UTC 2026-07-10 15:00 ~ 17:00 跨北京 7-10/7-11 两日。
	startMS := time.Date(2026, 7, 10, 15, 0, 0, 0, time.UTC).UnixMilli()
	endMS := time.Date(2026, 7, 10, 17, 0, 0, 0, time.UTC).UnixMilli()
	days := luckyGiftV3StatDays(startMS, endMS)
	if len(days) != 2 || days[0] != "2026-07-10" || days[1] != "2026-07-11" {
		t.Fatalf("days=%v, want [2026-07-10 2026-07-11]", days)
	}
	if got := luckyGiftV3StatDays(endMS, startMS); got != nil {
		t.Fatalf("inverted range must return nil, got %v", got)
	}
}
