%%%-------------------------------------------------------------------
%%% @doc    扭蛋全服幸运值管理进程
%%% Module  : mod_capsule_egg.erl
%%% Created : 2020-06-24
%%% @Author : tyl
%%%-------------------------------------------------------------------
-module(mod_capsule_egg).

-include("common.hrl").
-include("server.hrl").
-include("figure.hrl").
-include("role.hrl").
-include("capsule_egg.hrl").
-include("errcode.hrl").
-include("goods.hrl").
-include("def_module.hrl").
-include("def_goods.hrl").
-include("predefine.hrl").
-include("server_kv.hrl").
-include("custom_act.hrl").
-include("warsoul.hrl").

%% API
-export([
	capsule_egg_info/3      %% 查询扭蛋库全服信息
	,draw_capsule_egg/9     %% 抽奖
	,send_draw_reward/10    %% 发放奖励给玩家
	,weekly_clear/0         %% 每周一0点清理上周的抽奖记录
	,week_refresh/0         %% 每周一0点重置领奖次数
]).

-export([start_link/0, cast/1 ,call/1 ,info/1]).

%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).

%% API
%% 查询扭蛋库全服信息
capsule_egg_info(RoleId, PoolType, AddBuff) ->
	cast({get_capsule_egg_info, RoleId, PoolType, AddBuff}).

%% 抽奖
draw_capsule_egg(RoleId, PoolType, DrawTimes, HasDrawTimes, PerLuckyScore, TopPerLuckyScore, IsFree, CostList, AddBuff) ->
	cast({draw_capsule_egg, RoleId, PoolType, DrawTimes, HasDrawTimes, PerLuckyScore, TopPerLuckyScore, IsFree, CostList, AddBuff}).

%% 每周一0点清理上周的抽奖记录
weekly_clear() ->
	cast({weekly_clear}).

%% 每周一0点重置次数
week_refresh() ->
	cast({weekly_refresh}).

%% ---------------------------------------------------------------------------
start_link() ->
	gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).

cast(Msg) ->
	gen_server:cast(?MODULE, Msg).

call(Msg) ->
	gen_server:call(?MODULE, Msg).

info(Msg) ->
	erlang:send(?MODULE, Msg).

init([]) ->
	process_flag(trap_exit, true),
	State = init_capsule_egg_mod(),
	{ok, State}.

handle_call(Msg, From, State) ->
	try do_handle_call(Msg, From, State) of
		Reply ->
			Reply
	catch ?EXCEPTION(Class, Reason, StackTrace) ->
		Error = {Class, Reason, StackTrace},
		?ERR("~w:handle_call error:~p~n", [?MODULE, Error]),
		{error, Reason}
	end.

handle_cast(Msg, State) ->
	try do_handle_cast(Msg, State) of
		Result ->
			Result
	catch ?EXCEPTION(Class, Reason, StackTrace) ->
		Error = {Class, Reason, StackTrace},
		?ERR("~w:handle_cast error:~p~n", [?MODULE, Error]),
		{noreply, State}
	end.

handle_info(Info, State) ->
	try do_handle_info(Info, State) of
		Result ->
			Result
	catch ?EXCEPTION(Class, Reason, StackTrace) ->
		Error = {Class, Reason, StackTrace},
		?ERR("~w:handle_info error:~p~n", [?MODULE, Error]),
		{noreply, State}
	end.

terminate(_Reason, _State) ->
	ok.

code_change(_OldVsn, State, _Extra) ->
	{ok, State}.

%% ---------------------------------------------------------------------------
do_handle_call(_Msg, _From, State) ->
	{reply, ok, State}.

%% ---------------------------------------------------------------------------
do_handle_cast({get_capsule_egg_info, RoleId, PoolType, AddBuff}, State) ->
	get_capsule_egg_info(State, RoleId, PoolType, AddBuff),
	{noreply, State};

do_handle_cast({draw_capsule_egg, RoleId, PoolType, DrawTimes, HasDrawTimes, PerLuckyScore, TopPerLuckyScore, IsFree, CostList, AddBuff}, State) ->
	NewState = draw_capsule_egg_core(State, RoleId, PoolType, DrawTimes, HasDrawTimes, PerLuckyScore, TopPerLuckyScore, IsFree, CostList, AddBuff),
	{noreply, NewState};

do_handle_cast({weekly_clear}, State) ->
	clear_capsule_egg_log(),
	?ERR("Capsule egg weekly clear"),
	{noreply, State};

%% 如果周五-周日开发，则忽略这次更新
%% 周五 - 周六 - 周日 - 周一
%%  1      2      3      4
do_handle_cast({weekly_refresh}, State) ->
	OpenDay = util:get_open_day(),
	case OpenDay =< 4 of
		true -> ignore;
		_ ->
			lib_capsule_egg:weekly_refresh()
	end,
	{noreply, State};

do_handle_cast(_Msg, State) ->
	{noreply, State}.

%% ---------------------------------------------------------------------------
%% 此消息逻辑已废弃
do_handle_info({weekly_refresh}, State) ->
	#capsule_egg_state{weekly_refresh_ref = Ref} = State,
	lib_capsule_egg:weekly_refresh(),
	OpenDay  = util:get_open_day(),
	Now = utime:unixtime(),
	ServerKv = #server_kv{key = ?SERVER_KV_CAPSULE_EGG, value = OpenDay, time = Now},
	lib_server_kv:update_server_kv(ServerKv),
	AfterDate = utime:that_day_after(7),
	NewRef = util:send_after(Ref, max(0, AfterDate - Now)*1000, self(), {weekly_refresh}),
	{noreply, State#capsule_egg_state{weekly_refresh_ref = NewRef}};

do_handle_info(_Info, State) ->
	?ERR("Handle unknow msg[~w]~n", [_Info]),
	{noreply, State}.


%% ---------------------- builtin function -------------------------------------------
init_capsule_egg_mod() ->
	case lib_capsule_egg:get_db_server_score() of
		[_|_] = ScoreList ->
			ServerScoreMap = make_score_map(ScoreList, #{}),
			ShowScoreMap   = make_show_score_map(ScoreList, #{});
		_ ->
			ServerScoreMap = #{},
			ShowScoreMap   = #{}
	end,
	NowTime = utime:unixtime(),
	%% 普通记录
	TimeStamp =
	case data_capsule_egg:get_capsule_egg_kv_cfg(tv_show_time) of
		SInterval when is_integer(SInterval) ->
			NowTime - SInterval;
		_ ->
			NowTime - 2*?ONE_DAY_SECONDS
	end,
	DrawLogMap =
	case lib_capsule_egg:get_db_draw_log(TimeStamp, ?TV_TWO) of
		[_|_] = LogList ->
			make_log_map(LogList, #{});
		_ ->
			#{}
	end,
	%% 置顶记录
	TimeStamp1 =
	case data_capsule_egg:get_capsule_egg_kv_cfg(tv_topshow_time) of
		Interval when is_integer(Interval) ->
			NowTime - Interval;
		_ -> NowTime - 7*?ONE_DAY_SECONDS
	end,
	TopLogMap =
	case lib_capsule_egg:get_db_top_draw_log(TimeStamp1, ?TV_ONE) of
		[_|_] = TopLogList ->
			make_log_map(TopLogList, #{});
		_ -> #{}
	end,
%%	%% 周期清理(7天为周期)
%%	OpenDay  = util:get_open_day(),
%%	FreshOpenDay = lib_server_kv:get_value(?SERVER_KV_CAPSULE_EGG, 0),
%%	case OpenDay == FreshOpenDay of
%%		true when FreshOpenDay > 0 -> %% 当天清理过,并且重启服务器
%%			%% 7天后更新
%%			AfterDate = utime:that_day_after(7),
%%			Now = utime:unixtime(),
%%			Ref = util:send_after([], max(0, AfterDate - Now)*1000, self(), {weekly_refresh});
%%		_ ->
%%			%% 获得第8天0点时间
%%			Value  = OpenDay rem 7,
%%			Value1 = case Value of
%%						0 -> 7;
%%						_ -> Value
%%			        end,
%%			AfterDay  = 7-Value1+1,
%%			AfterDate = utime:that_day_after(AfterDay),
%%			Now = utime:unixtime(),
%%			Ref = util:send_after([], max(0, AfterDate - Now)*1000, self(), {weekly_refresh})
%%	end,
	State = #capsule_egg_state{
		lucky_score_map = ServerScoreMap
		,record_map     = DrawLogMap
		,top_record_map = TopLogMap
		,show_lucky_map = ShowScoreMap
		% ,weekly_refresh_ref = Ref
	},
	State.

make_score_map([], Map) -> Map;
make_score_map([ScoreInfo|L], TMap) ->
	NewScoreMap = case ScoreInfo of
		              [PoolType, Score, _] ->
			              maps:put(PoolType, Score, TMap);
		              _ ->
			              TMap
	              end,
	make_score_map(L, NewScoreMap).

make_show_score_map([], Map) -> Map;
make_show_score_map([ScoreInfo|L], TMap) ->
	NewScoreMap = case ScoreInfo of
		              [PoolType, _, ShowScore] ->
			              maps:put(PoolType, ShowScore, TMap);
		              _ ->
			              TMap
	              end,
	make_show_score_map(L, NewScoreMap).

make_log_map([], Map) -> Map;
make_log_map([LogInfo|L], TMap) ->
	[PoolType, RoleId, RewardCfgId, _Color, Time] = LogInfo,
	case lib_capsule_egg:get_db_player_name(RoleId) of
		[RoleName] -> ok;
		_ -> RoleName = ""
	end,
	DrawRecord =
	#draw_record{
		pool_type  = PoolType
		,role_id   = RoleId
		,role_name = RoleName
		,draw_time = Time
		,reward_cfg_id = RewardCfgId
	},
	DrawRecordList = maps:get(PoolType, TMap, []),
	NewDrawRecordList = [DrawRecord|DrawRecordList],
	NewLogMap = maps:put(PoolType, NewDrawRecordList, TMap),
	make_log_map(L, NewLogMap).

get_capsule_egg_info(State, RoleId, PoolType, AddBuff) ->
	#capsule_egg_state{show_lucky_map = ShowLuckyMap, record_map = RecordMap,
		top_record_map = TopRecordMap} = State,
	ServerLucky = maps:get(PoolType, ShowLuckyMap, 0),
	RecordList  = maps:get(PoolType, RecordMap, []),
	TopRecordList = maps:get(PoolType, TopRecordMap, []),
	NowTime = utime:unixtime(),
	DrawLogList = pack_draw_log(RecordList, NowTime, []),
	TopDrawLogList = pack_top_draw_log(TopRecordList, NowTime, []),
	DrawLogList1 = lists:sublist(DrawLogList, ?TV_TWO),
	TopDrawLogList1 = lists:sublist(TopDrawLogList, ?TV_ONE),
	%% 有buff加成的时候直接传999 展示部分前端处理
	case AddBuff > 0 of
		true -> ServerLucky1 = 999;
		_ -> ServerLucky1 = ServerLucky
	end,
	{ok, BinData} = pt_170:write(17001, [PoolType, ServerLucky1, DrawLogList1++TopDrawLogList1]),
	lib_server_send:send_to_uid(RoleId, BinData),
	ok.

pack_draw_log([], _NowTime, PackList) -> PackList;
pack_draw_log([DrawRecord|TList], NowTime, TPackList) ->
	case DrawRecord of
		#draw_record{
			role_id        = RoleId
			,role_name     = RoleName
			,reward_cfg_id = RewardCfgId
			,draw_time     = DrawTime
		} ->
			%% 过滤超过2*24小时的记录
			Interval =
			case data_capsule_egg:get_capsule_egg_kv_cfg(tv_show_time) of
				SInterval when is_integer(SInterval) -> SInterval;
				_ -> 2*?ONE_DAY_SECONDS
			end,
			case DrawTime + Interval =< NowTime of
				true ->
					pack_draw_log(TList, NowTime, TPackList);
				_ ->
					pack_draw_log(TList, NowTime, [{RoleId, RoleName, RewardCfgId, DrawTime, 0}|TPackList])
			end;
		_ ->
			pack_draw_log(TList, NowTime, TPackList)
	end.

pack_top_draw_log([], _NowTime, PackList) -> PackList;
pack_top_draw_log([DrawRecord|TList], NowTime, TPackList) ->
	case DrawRecord of
		#draw_record{
			role_id        = RoleId
			,role_name     = RoleName
			,reward_cfg_id = RewardCfgId
			,draw_time     = DrawTime
		} ->
			%% 过滤超过7*24小时的记录
			Interval =
			case data_capsule_egg:get_capsule_egg_kv_cfg(tv_topshow_time) of
				SInterval when is_integer(SInterval) -> SInterval;
				_ -> 7*?ONE_DAY_SECONDS
			end,
			case DrawTime + Interval =< NowTime of
				true ->
					pack_top_draw_log(TList, NowTime, TPackList);
				_ ->
					pack_top_draw_log(TList, NowTime, [{RoleId, RoleName, RewardCfgId, DrawTime, 1}|TPackList])
			end;
		_ ->
			pack_top_draw_log(TList, NowTime, TPackList)
	end.

draw_capsule_egg_core(State, RoleId, PoolType, DrawTimes, HasDrawTimes, PerLuckyScore, TopPerLuckyScore, IsFree, CostList, AddBuff) ->
	#capsule_egg_state{lucky_score_map = LuckyScoreMap, show_lucky_map = ShowScoreMap,
		record_map = RecordMap, top_record_map = TopRecordMap
	} = State,
	LuckyScore    = maps:get(PoolType, LuckyScoreMap, 0),
	ShowScore     = maps:get(PoolType, ShowScoreMap, 0),
	RecordList    = maps:get(PoolType, RecordMap, []),
	TopRecordList = maps:get(PoolType, TopRecordMap, []),
	{NewLuckyScore, NewPerLuckyScore, NewTopPerLuckScore, NewDrawTimes, NewShowScore, RewardList, CfgMsgList} =
		calc_send_reward(PoolType, LuckyScore,PerLuckyScore, TopPerLuckyScore, HasDrawTimes, ShowScore, DrawTimes, [], [], AddBuff),
	NewLuckyScoreMap    = maps:put(PoolType, NewLuckyScore, LuckyScoreMap),
	%% 到玩家进程发放礼物,玩家离线发放到邮件
	lib_player:apply_cast(RoleId, ?APPLY_CAST_SAVE, ?HAND_OFFLINE, ?MODULE, send_draw_reward,
		[PoolType, DrawTimes, NewDrawTimes, NewPerLuckyScore, NewTopPerLuckScore, RewardList, CfgMsgList, IsFree, CostList]
	),
	%% 全服记录
	RecordTime = utime:unixtime(),
	{AddRecordL, AddTopRecordL} = make_draw_record(PoolType, RoleId, CfgMsgList, RecordTime),
	%% 限制记录条数
	NewTopRecordList = lists:sublist(lists:reverse(lists:keysort(#draw_record.draw_time, TopRecordList++AddTopRecordL)), ?TV_ONE),
	NewRecordList = lists:sublist(lists:reverse(lists:keysort(#draw_record.draw_time, RecordList ++ AddRecordL)), ?TV_TWO),
	NewRecordMap = maps:put(PoolType, NewRecordList, RecordMap),
	NewTopRecordMap = maps:put(PoolType, NewTopRecordList, TopRecordMap),
	NewShowScoreMap = maps:put(PoolType, NewShowScore, ShowScoreMap),
	%% 存库
	lib_capsule_egg:save_db_server_score(PoolType, NewLuckyScore, NewShowScore),
	spawn(fun() -> batch_save_draw_log(PoolType, RoleId, CfgMsgList, RecordTime) end),
	%% 全服广播
	send_server_lucky_score(PoolType, NewShowScore, AddBuff),
	CfgMsgList =/= [] andalso send_tv_to_all(PoolType, NewShowScore, RoleId, CfgMsgList, RecordTime, AddBuff),
	State#capsule_egg_state{lucky_score_map = NewLuckyScoreMap, show_lucky_map = NewShowScoreMap,
		record_map = NewRecordMap, top_record_map = NewTopRecordMap
	}.

%% 玩家进程发放礼物
send_draw_reward(Player, PoolType, DrawTimes, NewDrawTimes, NewPerLuckyScore, NewTopLuckyScore, RewardList, CfgMsgList, IsFree, CostList) ->
	#player_status{capsule_egg = StatusCapsuleEgg, sid = Sid, id = RoleId, figure = Figure} = Player,
	RewardList1 = lib_goods_util:merge_same_goods(RewardList),
	% RewardList2 = [{location, ?GOODS_LOC_CAPSULE_EGG_BAG, GTypeId, TNum}||{_, GTypeId, TNum}<-RewardList1],
	%% 物品投放到龙神仓库,背包格子不足等情况直接发邮件,保证发放到手
	%case catch lib_goods_api:give_goods_with_loc(Player, ?GOODS_LOC_CAPSULE_EGG_BAG, RewardList2, draw_capsule_egg, 0) of
	%	{ErrorCode, _GoodsInfoList} when ErrorCode == 1 ->
	%		skip;
	%	_Res ->
	%		lib_mail_api:send_sys_mail([RoleId], ?MOD_CAPSULE_EGG, utext:get(11), utext:get(12), RewardList1)
	%end,
	%% 背包不足直接放邮件
	Product = #produce{type = draw_capsule_egg, reward = RewardList1},
	{ok, Player1} = lib_goods_api:send_reward_with_mail(Player, Product),
	#status_capsule_egg{score = Score, capsule_egg_map = CapsuleEggMap} = StatusCapsuleEgg,
	case maps:get(PoolType, CapsuleEggMap, []) of
		#capsule_egg_data{next_free_time = NextFreeTime} = CapsuleEggData ->
			skip;
		_ ->
			CapsuleEggData = #capsule_egg_data{}, NextFreeTime = 0
	end,
	NewScore = Score + DrawTimes,
	NewCapsuleEggData = CapsuleEggData#capsule_egg_data{
		draw_times = NewDrawTimes, lucky_score = NewPerLuckyScore, top_lucky_score = NewTopLuckyScore
	},
	NewCapsuleEggMap  = maps:put(PoolType, NewCapsuleEggData, CapsuleEggMap),
	NewStatusCapsuleEgg = StatusCapsuleEgg#status_capsule_egg{capsule_egg_map = NewCapsuleEggMap, score = NewScore},
	RewardIdList = [RewardId||{RewardId, _Color}<-CfgMsgList],
	%% 传闻
	spawn(fun() -> timer:sleep(6000), lists:map(fun(SRewardId) ->
		case data_capsule_egg:get_capsule_egg_reward_cfg(SRewardId) of
			#capsule_egg_reward_cfg{color = SColor, reward = [{_, SGTypeId, _}]} when SColor =< 2 ->
				lib_chat:send_TV({all}, ?MOD_CAPSULE_EGG, PoolType, [Figure#figure.name, RoleId, SGTypeId]);
			_ ->
				skip
		end end, RewardIdList) end),
	F = fun(TRewardId, TPackL) ->
		case data_capsule_egg:get_capsule_egg_reward_cfg(TRewardId) of
			#capsule_egg_reward_cfg{reward = [{_, GoodTypeId, Num}]} ->
				[{TRewardId, GoodTypeId, Num}|TPackL];
			_ ->
				TPackL
		end end,
	PackRewardL = lists:foldl(F, [], RewardIdList),
	FreeTimes = case NextFreeTime =< utime:unixtime() of true -> 1; _ -> 0 end,
	%% 增加积分&抽奖次数
	lib_capsule_egg:save_db_person_score(RoleId, NewScore),   %% 积分
	lib_capsule_egg:save_db_capsule_egg(RoleId, PoolType, NextFreeTime, NewDrawTimes, NewPerLuckyScore, NewTopLuckyScore),  %% 抽奖数据
	NewPlayer =	Player1#player_status{capsule_egg = NewStatusCapsuleEgg},
	Pid = misc:get_player_process(RoleId),
	case is_pid(Pid) andalso misc:is_process_alive(Pid) of
		true ->
			lib_capsule_egg:send_msg(Sid, 17003, [?SUCCESS, PoolType, FreeTimes, NextFreeTime, PackRewardL, NewDrawTimes]),
			case IsFree == 1 of
				true ->
					lib_capsule_egg:send_msg(Sid, 17004, [Score]);
				_ ->
					lib_capsule_egg:send_msg(Sid, 17004, [NewScore])
			end;
		_ -> skip
	end,
	%% 日志
	ColorMax = case CfgMsgList =/= [] of
		           true -> lists:min([TColor||{_RewardId, TColor}<-CfgMsgList]);
		           _ -> 0
	           end,
	Absolute = absolute_color(PoolType, CapsuleEggData#capsule_egg_data.draw_times+1, NewDrawTimes),
	lib_log_api:log_capsule_egg_draw(RoleId, PoolType, trans_type(DrawTimes), RewardList, ColorMax, Absolute, CostList),
	{PurpleNum, Orange4, Orange5, Red, IsPrize} = calc_color_num(RewardIdList),
	CostGold = case lists:keyfind(?TYPE_GOLD, 1, CostList) of
		           {_, _, GoldNum} -> GoldNum;
				   _ -> 0
	           end,
	CostTicketNum = case lists:keyfind(?TYPE_GOODS, 1, CostList) of
		                {_, TicketId, TicketNum} ->
			                case DrawTimes of
				                10 when TicketId == 102306 -> 9;
				                10 when TicketId == 102305 -> TicketNum;
				                _ -> 1
			                end;
		                _ ->
			                0
	                end,
	[{_, OwnNum1}] = lib_goods_api:get_goods_num(NewPlayer, [102305]),
	[{_, OwnNum2}] = lib_goods_api:get_goods_num(NewPlayer, [102306]),
	TARewardIdList =
	case PackRewardL of
		[{_, _, _}|_] -> [TGoodsId||{_, TGoodsId, _}<-PackRewardL];
		_ -> []
	end,
	ta_agent_fire:warsoul_draw(NewPlayer, [draw_name(DrawTimes), TARewardIdList, PurpleNum, Orange4, Orange5, Red, IsPrize, Absolute,
		NewDrawTimes, CostGold, CostTicketNum, NewPlayer#player_status.gold, OwnNum1+OwnNum2*9]),
	{ok, NewPlayer}.

draw_name(DrawTimes) ->
	case DrawTimes  of
		10 -> "十连";
		_ -> "单抽"
	end.

calc_color_num(AwardList) ->
	F = fun(AwardId, {TPurpleNum, TOrange4, TOrange5, TRed, TIsPrize}) ->
		case data_capsule_egg:get_capsule_egg_reward_cfg(AwardId) of
			#capsule_egg_reward_cfg{reward = [{_, GoodsId, _}|_], color = PrizeColor} ->
				case data_warsoul:get_war_soul_info(GoodsId) of
					#base_war_soul_info{type = Type, color = Color, star = Star} ->
						case Type of
							999 ->
								{TPurpleNum, TOrange4, TOrange5, TRed, TIsPrize};
							_ ->
								TIsPrize1 =
								case PrizeColor of
									0 -> 1;
									_ -> 0
								end,
								case Color of
									3 when Star == 3 ->
										{TPurpleNum+1, TOrange4, TOrange5, TRed, TIsPrize1};
									4 when Star == 4 ->
										{TPurpleNum, TOrange4+1, TOrange5, TRed, TIsPrize1};
									4 when Star == 5 ->
										{TPurpleNum, TOrange4, TOrange5+1, TRed, TIsPrize1};
									5 when Star == 5 ->
										{TPurpleNum, TOrange4, TOrange5, TRed+1, TIsPrize1};
									_ ->
										{TPurpleNum, TOrange4, TOrange5, TRed, TIsPrize1}
								end
						end;
					_ ->
						{TPurpleNum, TOrange4, TOrange5, TRed, TIsPrize}
				end;
			_ ->
				{TPurpleNum, TOrange4, TOrange5, TRed, TIsPrize}
		end end,
	{PurpleNum, Orange4, Orange5, Red, IsPrize} = lists:foldl(F, {0, 0, 0, 0, 0}, AwardList),
	{PurpleNum, Orange4, Orange5, Red, IsPrize}.

%% 日志记录的抽奖类型
trans_type(DrawTimes) ->
	case DrawTimes of
		1  -> 1;
		10 -> 2;
		50 -> 3;
		_  -> 1
	end.

%% 日志记录次数必得档位
absolute_color(PoolType, DrawTimes, NewDrawTimes) ->
	MustList = data_capsule_egg:get_all_must_times_cfg(PoolType),
	F = fun(MustTime, Ack) ->
		case DrawTimes =< MustTime andalso NewDrawTimes >= MustTime of
			true -> 1;
			_ -> Ack
		end end,
	IsMust = lists:foldl(F, 0, MustList),
	IsMust.

%% 构造全服记录格式
make_draw_record(PoolType, RoleId, CfgMsgList, RecordTime) ->
	case lib_role:get_role_show(RoleId) of
		#ets_role_show{figure = Figure} ->
			#figure{name = RoleName} = Figure;
		_ -> RoleName = ""
	end,
	F = fun({RewardId, Color}, {TRecordList, TTopRecordList}) ->
		DrawRecord = #draw_record{
			pool_type  = PoolType
			,role_id   = RoleId
			,role_name = RoleName
			,reward_cfg_id = RewardId
			,draw_time = RecordTime
		},
		case Color == ?TV_GRADE of
			%% 二类(3档)
			true ->
				{[DrawRecord|TRecordList], TTopRecordList};
			%% 一类(1/2档)
			_ ->
				case Color =< ?TV_TOP of
					true ->
						{TRecordList, [DrawRecord|TTopRecordList]};
					_ ->
						{TRecordList, TTopRecordList}
				end
		end end,
	lists:foldl(F, {[], []}, CfgMsgList).

send_server_lucky_score(PoolType, ShowScore, AddBuff) ->
	case AddBuff > 0 of
		true -> ShowScore1 = 999;
		_ -> ShowScore1 = ShowScore
	end,
	{ok, BinData} = pt_170:write(17010, [PoolType, ShowScore1]),
	lib_server_send:send_to_all(BinData).

send_tv_to_all(PoolType, ShowScore, RoleId, CfgMsgList, RecordTime, AddBuff) ->
	case AddBuff > 0 of
		true -> ShowScore1 = 999;
		_ -> ShowScore1 = ShowScore
	end,
	case lib_role:get_role_show(RoleId) of
		#ets_role_show{figure = Figure} ->
			#figure{name = RoleName} = Figure;
		_ -> RoleName = ""
	end,
	RewardIdList = lists:foldl(
		fun({RewardId, Color}, TList) when Color =< ?TV_TOP ->
				IsTicket = 1,
				[{RewardId, IsTicket}|TList];
			({RewardId, Color}, TList) when Color == ?TV_GRADE ->
				IsTicket = 0,
				[{RewardId, IsTicket}|TList];
			(_, TList) ->
				TList
			end, [], CfgMsgList),
	SendMsg = [PoolType, ShowScore1, RoleId, RoleName, RewardIdList, RecordTime],
	{ok, BinData} = pt_170:write(17002, SendMsg),
	%% 开启了扭蛋功能的玩家才能收到广播，减少广播的数量  %% TODO
	%  lib_server_send:send_to_all(all_lv, {OpenLv, 99999999}, BinData) end,
	lib_server_send:send_to_all(BinData).

%% 抽奖记录批量插入
batch_save_draw_log(PoolType, RoleId, CfgMsgList, RecordTime) ->
	F = fun({RewardId, Color}, TSqlList) when Color =< ?TV_GRADE  ->
				TSql = io_lib:format(?SQL_BATCH_INSERT_CAPSULE_EGG_DRAW_LOG_VALUE, [PoolType, RoleId, RewardId, Color, RecordTime]),
				[TSql|TSqlList];
			(_, TSqlList) -> TSqlList
	    end,
	NewSQLs = lists:foldl(F, [], CfgMsgList),
	if
		NewSQLs =/= [] ->
			NewValues = util:join_bitstring(NewSQLs, <<", ">>),
			FinalSql = io_lib:format(?SQL_BATCH_INSERT_CAPSULE_EGG_DRAW_LOG, [NewValues]),
			db:execute(FinalSql);
		true -> skip
	end.

%%----------------------------------------------------------------------
%% @doc 计算抽奖奖励
-spec calc_send_reward(PoolType, LuckyScore, PerLuckyScore, TopPerLuckyScore, HasDrawTimes, ShowScore, DrawTimes, RewardList, CfgMsgList, AddBuff) -> Return when
	PoolType          :: integer(),     % 奖池库
	LuckyScore        :: integer(),     % 全服幸运值(用于计算动态概率)
	PerLuckyScore     :: integer(),     % 个人幸运值(用于计算动态概率)
	TopPerLuckyScore  :: integer(),     % 0档个人幸运值(用于计算动态概率)
	HasDrawTimes      :: integer(),     % 玩家已经抽奖次数(用于计算必得档位)
	ShowScore         :: integer(),     % 前端展示全服幸运值
    DrawTimes         :: integer(),     % 本次抽奖次数
	RewardList        :: list(),        % 奖励列表
	CfgMsgList        :: list(),        % 奖励档位信息 格式:[{RewardId, Color}...]
	AddBuff           :: integer(),     % 活动增加权重(固定全服权重)
    Return            :: tuple().       % {LuckyScore, PerLuckyScore, TopPerLuckyScore, HasDrawTimes, ShowScore, RewardList, CfgMsgList}
%% @end
%%----------------------------------------------------------------------
calc_send_reward(_PoolType, LuckyScore, PerLuckyScore, TopPerLuckyScore, HasDrawTimes, ShowScore, 0, RewardList, CfgMsgList, _AddBuff) ->
	{LuckyScore, PerLuckyScore, TopPerLuckyScore, HasDrawTimes, ShowScore, RewardList, CfgMsgList};
calc_send_reward(PoolType, LuckyScore, PerLuckyScore, TopPerLuckyScore, HasDrawTimes, ShowScore, DrawTimes, TRewardList, TCfgMsgList, AddBuff) ->
	NewDrawTimes  = HasDrawTimes + 1,
	NewLuckyScore = LuckyScore + 1,
	NewPerLuckyScore = PerLuckyScore + 1,
	NewTopPerLuckyScore = TopPerLuckyScore + 1,
	NewShowScore = ShowScore + 1,
	case data_capsule_egg:get_capsule_egg_times_cfg(PoolType, NewDrawTimes) of
		[Color|_] -> %% 必得xx档位奖励
			RewardIdList = data_capsule_egg:get_capsule_egg_reward_sublist_cfg(PoolType, Color);
		_ ->
			RewardIdList = data_capsule_egg:get_capsule_egg_reward_list_cfg(PoolType)
	end,
	{RewardCfgList, SumWeight} = trans_to_rand_list(
		PoolType, NewLuckyScore, NewPerLuckyScore, NewTopPerLuckyScore, RewardIdList, [], 0, AddBuff
	),
	%% 由于权重修改,需要重新筛选剔除权重为0的 以及 重新排序权重列表
	RewardCfgList1 = [{TWeight, TId}||{TWeight, TId} <- RewardCfgList, TWeight > 0],
	RewardCfgList2 = lists:reverse(lists:keysort(1, RewardCfgList1)),
	RandRewardId = rand_reward(RewardCfgList2, SumWeight),
	%% 玩家抽到0/1/2档(读配置)奖励,全服幸运值 & 个人幸运值清0
	%% 抽到0/1档,前端展示的全服幸运值(show_score)清0
	ClearColor = case data_capsule_egg:get_ratio_color(PoolType) of
		             TClear when is_integer(TClear), TClear > 0 -> TClear;
					 _ -> 1
	             end,
	case data_capsule_egg:get_capsule_egg_reward_cfg(RandRewardId) of
		#capsule_egg_reward_cfg{color = TColor} when TColor > 0, TColor =< ClearColor ->
			NewLuckyScore1 = 0,
			NewPerLuckyScore1 = 0,
			NewTopPerLuckyScore1 = NewTopPerLuckyScore,
			case TColor =< 1 of
				true -> NewShowScore1 = 0;
				_ -> NewShowScore1 = min(NewShowScore, ?SERVER_MAX_LUCKY)
			end;
		#capsule_egg_reward_cfg{color = TColor} when TColor == 0 ->
			NewLuckyScore1    = 0,
			NewPerLuckyScore1 = 0,
			NewTopPerLuckyScore1 = 0,
			NewShowScore1 = 0;
		_ ->
			NewLuckyScore1 = min(NewLuckyScore, ?SERVER_MAX_LUCKY),
			NewPerLuckyScore1 = NewPerLuckyScore,
			NewTopPerLuckyScore1 = NewTopPerLuckyScore,
			NewShowScore1 = min(NewShowScore, ?SERVER_MAX_LUCKY)
	end,
	%% 超级大奖额外赠送一个坐骑
	case is_integer(RandRewardId) of
		true ->
			case data_capsule_egg:get_capsule_egg_reward_cfg(RandRewardId) of
				#capsule_egg_reward_cfg{reward = RandReward, color = TColor1, client_pos = ClientPos} ->
					case ClientPos of
						1 -> RandReward1 = RandReward ++ data_capsule_egg:get_capsule_egg_kv_cfg(giving_reward);
						_ -> RandReward1 = RandReward
					end,
					CfgMsg = [{RandRewardId, TColor1}];
				_ ->
					RandReward1 = [], CfgMsg = []
			end,
			calc_send_reward(PoolType, NewLuckyScore1, NewPerLuckyScore1, NewTopPerLuckyScore1, NewDrawTimes, NewShowScore1, DrawTimes-1, TRewardList++RandReward1, TCfgMsgList++CfgMsg, AddBuff);
		_ ->
			calc_send_reward(PoolType, NewLuckyScore1, NewPerLuckyScore, NewTopPerLuckyScore, NewDrawTimes, NewShowScore1, DrawTimes-1, TRewardList, TCfgMsgList, AddBuff)
	end.


%% 随机出奖励
%% 计算公式：
%% 物品概率 = 权重 / 总权重
%% 权重 = 随机基础权重 + 个人权重加成 + 全服权重加成
%% 总权重 = 基础权重 + 个人权重加成 + 全服权重加成 总和
%% 个人权重 和 全服权重 -- 根据物品品质有不同加成,每个物品的加成都一样
%% @Param
%%  WeightList: [{Weight, RewardId}...]
%%  RandAdd: 全服权重加成+个人权重加成
%%  Sum: 总权重
rand_reward([], _) -> false;
rand_reward(WeightList, BaseSum) ->
	Rand = urand:rand(1, BaseSum),
	rand_with_percent_get_elem(WeightList, Rand, 0).
%% 获取对应的随机项
rand_with_percent_get_elem([], _, _) -> false;
rand_with_percent_get_elem([{Weight, Elem}|T], Rand, I) ->
	case Rand =< Weight+I of
		true  -> Elem;
		false -> rand_with_percent_get_elem(T, Rand, Weight+I)
	end.

trans_to_rand_list(_PoolType, _LuckyScore,  _PerLuckyScore, _TopPerLuckyScore, [], WeightList, SumWeight, _AddBuff) ->
	{WeightList, SumWeight};
trans_to_rand_list(PoolType, LuckyScore, PerLuckyScore, TopPerLuckyScore, [RewardId|L], WeightList, TSumWeight, AddBuff) ->
	case data_capsule_egg:get_capsule_egg_reward_cfg(RewardId) of
		#capsule_egg_reward_cfg{weight = Weight, color = Color} ->
			case Color == 0 of
				true ->
					TruePerLuckyScore  = TopPerLuckyScore;
				_ ->
					TruePerLuckyScore = PerLuckyScore
			end,
			case data_capsule_egg:get_capsule_egg_ratio_cfg(PoolType, ?RAND_ADD_PERSONAL, Color, TruePerLuckyScore) of
				PersonalRandAdd when is_integer(PersonalRandAdd) -> skip;
				_ -> PersonalRandAdd = 0
			end,
			case data_capsule_egg:get_capsule_egg_ratio_cfg(PoolType, ?RAND_ADD_SERVER, Color, LuckyScore) of
				ServerRandAdd when is_integer(ServerRandAdd) -> skip;
				_ -> ServerRandAdd = 0
			end,
			ExtraAdd = case lists:member(Color, [0, 1, 2]) of
						   true -> AddBuff/100;
						   _ -> 0
			           end,
			AddRatio = PersonalRandAdd/100 + ServerRandAdd/100 + ExtraAdd,
			TrueWeight = round(Weight * (1+AddRatio)),
			trans_to_rand_list(PoolType, LuckyScore, PerLuckyScore, TopPerLuckyScore, L, [{TrueWeight, RewardId}|WeightList], TSumWeight+TrueWeight, AddBuff);
		_ ->
			trans_to_rand_list(PoolType, LuckyScore, PerLuckyScore, TopPerLuckyScore, L, WeightList, TSumWeight, AddBuff)
	end.

%% 清理一周前数据
clear_capsule_egg_log() ->
	%% 只清理数据库,内存数据不清理
	%% (这里没有兼容夏令时,但问题并不大,只是清理记录)
	case data_capsule_egg:get_capsule_egg_kv_cfg(tv_topshow_time) of
		Integer when is_integer(Integer) -> ok;
		_ -> Integer = 7*?ONE_DAY_SECONDS
	end,
	NowTime = utime:unixtime(),
	ClearTime = max(0, NowTime - Integer),
	Sql = io_lib:format(<<"delete from capsule_egg_draw_log where `time` <= ~p">>,[ClearTime]),
	db:execute(Sql),
	ok.