%%%-------------------------------------------------------------------
%%% @doc     刮刮卡-逻辑文件
%%% Module  : scratch_card.erl
%%% Created : 2020-10-13
%%% @end
%%% @author : tyl
%%%-------------------------------------------------------------------
-module(scratch_card).

-include("scratch_card.hrl").
-include("custom_act.hrl").
-include("server.hrl").
-include("common.hrl").
-include("def_module.hrl").
-include("predefine.hrl").
-include("def_goods.hrl").
-include("goods.hrl").
-include("figure.hrl").
-include("errcode.hrl").

%% API
-export([
	get_scratch_card_info/2         %% 刮卡信息
	,scratch_card/4                 %% 刮卡
	,get_draw_info/2                %% 抽奖信息
	,refresh_scratch_card/2         %% 刷新抽奖信息
	,score_draw/2                   %% 抽奖
	,send_scratch_tv/2              %% 延迟推送刮卡大奖传闻
	,gm_add_scratch_score/3         %% gm增加抽奖积分
]).

%% -------------------------------------------------------------------
%% @doc 刮卡信息 @end
%% -------------------------------------------------------------------
get_scratch_card_info(Player, SubType) ->
	case lib_custom_act_api:is_open_act(?CUSTOM_ACT_TYPE_SCRATCH_CARD, SubType) of
		true ->
			#custom_act_data{act_data = ActData} =
				lib_custom_act_data:custom_act_data(?CUSTOM_ACT_TYPE_SCRATCH_CARD, SubType),
			case ActData of
				#scratch_card_data{card_list = CardList} ->
					PackRewardList = pack_scratch_reward(SubType, CardList);
				_  ->
					PackRewardList = []
			end,
			PackBaseReward = pack_scratch_base_reward(SubType),
			lib_server_send:send_to_sid(
				Player#player_status.sid, pt_332, 33244, [SubType, PackRewardList, PackBaseReward]
			);
		false ->
			lib_server_send:send_to_sid(
				Player#player_status.sid, pt_331, 33100, [?ERRCODE(err331_act_closed)]
			)
	end,
	ok.

%% 打包刮过的奖励列表
pack_scratch_reward(SubType, CardList) ->
	F = fun({Pos, GradeId}, AccList) ->
		case lib_custom_act_util:get_act_reward_cfg_info(?CUSTOM_ACT_TYPE_SCRATCH_CARD, SubType, GradeId) of
			#custom_act_reward_cfg{reward = Reward} ->
				PackReward = [{GoodTypeId, Num}||{_, GoodTypeId, Num}<-Reward],
				[{Pos, PackReward}|AccList];
			_ ->
				AccList
		end end,
	PackList = lists:foldl(F, [], CardList),
	PackList.

%% 打包刮奖库奖励列表
pack_scratch_base_reward(SubType) ->
	RewardList = lib_custom_act_util:get_act_reward_grade_list(?CUSTOM_ACT_TYPE_SCRATCH_CARD, SubType),
	F = fun(GradeId, AccList) ->
		case lib_custom_act_util:get_act_reward_cfg_info(?CUSTOM_ACT_TYPE_SCRATCH_CARD, SubType, GradeId) of
			#custom_act_reward_cfg{condition = Condition, reward = Reward} ->
				case lists:keyfind(type, 1, Condition) of
					{type, 1} ->
						case lists:keyfind(tv_show, 1, Condition) of
							{_, IsShow} when IsShow == 1 ->
								PackReward = [{GoodTypeId, Num}||{_, GoodTypeId, Num}<-Reward],
								PackReward ++ AccList;
							_ ->
								AccList
						end;
					_ ->
						AccList
				end;
			_ ->
				AccList
		end end,
	PackList = lists:foldl(F, [], RewardList),
	PackList.

%% -------------------------------------------------------------------
%% @doc 刮卡 Option: 1-指定刮奖 2-随机刮奖 3-全部刮奖 @end
%% -------------------------------------------------------------------
scratch_card(Player, SubType, Option, Pos) ->
	#player_status{id = RoleId, figure = Figure} = Player,
	case lib_custom_act_api:is_open_act(?CUSTOM_ACT_TYPE_SCRATCH_CARD, SubType) of
		true ->
			#custom_act_data{act_data = ActData} = CustomActData =
				lib_custom_act_data:custom_act_data(?CUSTOM_ACT_TYPE_SCRATCH_CARD, SubType),
			%% 检查配置
			{CheckCost, Cost} = check_scratch_cost(SubType),
			%% 检查是否已经刮完
			CheckAllScratch = check_has_scratch_all(ActData),
			%% 检查操作类型
			CheckOption = check_scratch_option(Option),
			%% 检查位置
			CheckPos = check_scratch_pos(ActData, Option, Pos),
			%% 检查buff加成次数
			{BuffFree, BuffCount} = check_buff_count(Player),
			%% 检查材料/钻石是否足够
			{CheckMaterial, TrueCost, CostBuffFree, CostBuffCount} =
				check_material_enough(Player, Option, ActData, Cost, BuffFree, BuffCount),
			{ScratchReward, _, _} = part_scratch_reward(SubType),
			if
				CheckCost == false ->
					lib_server_send:send_to_sid(
						Player#player_status.sid, pt_331, 33100, [?ERRCODE(config_err)]
					),
					{ok, Player};
				CheckAllScratch == false ->
					lib_server_send:send_to_sid(
						Player#player_status.sid, pt_331, 33100, [?ERRCODE(err331_all_scratch)]
					),
					{ok, Player};
				CheckOption == false ->
					lib_server_send:send_to_sid(
						Player#player_status.sid, pt_331, 33100, [?ERRCODE(err331_scratch_option_err)]
					),
					{ok, Player};
				CheckPos == false ->
					lib_server_send:send_to_sid(
						Player#player_status.sid, pt_331, 33100, [?ERRCODE(err331_scratch_pos_err)]
					),
					{ok, Player};
				ScratchReward == [] ->
					lib_server_send:send_to_sid(
						Player#player_status.sid, pt_331, 33100, [?ERRCODE(err331_scratch_reward_err)]
					),
					{ok, Player};
				CheckMaterial == false ->
					lib_server_send:send_to_sid(
						Player#player_status.sid, pt_331, 33100, [?ERRCODE(err331_scratch_cost_not_enough)]
					),
					{ok, Player};
				true ->
					{NewActData, RewardList, PackRewardL, TvShowList} =
						scratch_card_core(SubType, ActData, Option, Pos, ScratchReward),
					%% buff加成后可能会免费
					Return = case TrueCost of
						         [] ->
							         {true, Player};
						         _ ->
							         %% 检查材料是否足够
							         case lib_goods_api:cost_object_list_with_check(Player, TrueCost, scratch_card, "") of
								         {true, TPlayer, _} ->
									         {true, TPlayer};
								         {false, TErr, _} ->
									         {false, TErr}
							         end
					         end,
					case Return of
						{true, Player1} ->
							NewCustomActData = CustomActData#custom_act_data{act_data = NewActData},
							Produce = #produce{reward = RewardList, type = scratch_card},
							{ok, NewPlayer} = lib_goods_api:send_reward_with_mail(Player1, Produce, ?MOD_AC_CUSTOM),
							lib_custom_act_data:save_custom_data(RoleId, NewCustomActData),
							case TvShowList =/= [] of
								true ->
									case Option =/= ?FIX_SCRATCH of
										true -> notice_tv(scratch, SubType, Figure#figure.name, TvShowList);
										%% 延迟发送
										_ -> util:send_after([], 5*1000, self(), {'mod', ?MODULE, send_scratch_tv, [SubType]})
									end;
								_ -> ignore
							end,
							#scratch_card_data{score = NewScore} = NewActData,
							lib_server_send:send_to_sid(
								Player#player_status.sid, pt_332, 33245, [?SUCCESS, SubType, Option, NewScore, PackRewardL]
							),
							%% 扣取buff加成次数
							CostBuffFree > 0 andalso custom_unite_buff:cost_times(NewPlayer, activity_free, 108, CostBuffFree),
							CostBuffCount >0 andalso custom_unite_buff:cost_times(NewPlayer, activity_discount, 108, CostBuffCount),
							log_send_goods(NewPlayer, Player, ?CUSTOM_ACT_TYPE_SCRATCH_CARD, SubType, "scratch_card", RewardList),
							{ok, NewPlayer};
						{false, Err} ->
							lib_server_send:send_to_sid(Player#player_status.sid, pt_331, 33100, [Err]),
							{ok, Player}
					end
			end;
		false ->
			lib_server_send:send_to_sid(Player#player_status.sid, pt_331, 33100, [?ERRCODE(err331_act_closed)]),
			{ok, Player}
	end.

%% buff加成
check_buff_count(Player) ->
	%% 是否有buff免费次数
	case custom_unite_buff:check_times(Player, activity_free, 108) of
		TNum0 when is_integer(TNum0) -> BuffFree = TNum0;
		_ -> BuffFree = 0
	end,
	%% 是否有buff加成次数
	case custom_unite_buff:check_times(Player, activity_discount, 108) of
		TNum when is_integer(TNum) -> BuffCount = TNum;
		_ -> BuffCount = 0
	end,
	{BuffFree, BuffCount}.

%% 延迟推送刮奖大奖传闻
send_scratch_tv(Player, SubType) ->
	#player_status{figure = Figure} = Player,
	case lib_custom_act_api:is_open_act(?CUSTOM_ACT_TYPE_SCRATCH_CARD, SubType) of
		true ->
			TvShowList = proc_get_tv_list(),
			case TvShowList of
				[{Pos, TvShows}|_] -> ok;
				_ -> Pos = 0, TvShows = []
			end,
			case Pos =/= 0 of
				true ->
					notice_tv(scratch, SubType, Figure#figure.name, TvShows),
					proc_put_tv_list([]),
					lib_server_send:send_to_sid(
						Player#player_status.sid, pt_332, 33249, [?SUCCESS, SubType, Pos]
					);
				_ ->
					lib_server_send:send_to_sid(
						Player#player_status.sid, pt_332, 33249, [?FAIL, SubType, Pos]
					)
			end;
		_ ->
			ignore
	end,
	{ok, Player}.

%% -------------------------------------------------------------------
%% 玩家进程 刮卡大奖奖励传闻
proc_get_tv_list() ->
	TvKey = ?SCRATCH_TV_LIST,
	case get(TvKey) of
		TvList when is_list(TvList) -> ok;
		_ -> TvList = []
	end,
	TvList.

proc_put_tv_list(TvList) when is_list(TvList) ->
	TvKey = ?SCRATCH_TV_LIST,
	put(TvKey, TvList);
proc_put_tv_list(_List) ->
	error.

%% -------------------------------------------------------------------
%% @doc 刷新刮卡卡片 @end
%% -------------------------------------------------------------------
refresh_scratch_card(Player, SubType) ->
	case lib_custom_act_api:is_open_act(?CUSTOM_ACT_TYPE_SCRATCH_CARD, SubType) of
		true ->
			#custom_act_data{act_data = ActData} = CustomActData =
				lib_custom_act_data:custom_act_data(?CUSTOM_ACT_TYPE_SCRATCH_CARD, SubType),
			case ActData of
				#scratch_card_data{card_list = CardList} ->
					case length(CardList) of
						?SCRATCH_MILL_STONE ->
							NewCardList = [],
							NewActData  = ActData#scratch_card_data{card_list = NewCardList},
							NewCustomActData = CustomActData#custom_act_data{act_data = NewActData},
							lib_server_send:send_to_sid(
								Player#player_status.sid, pt_332, 33248, [?SUCCESS, SubType]
							),
							lib_custom_act_data:save_custom_data(Player#player_status.id, NewCustomActData);
						_ ->
							lib_server_send:send_to_sid(
								Player#player_status.sid, pt_331, 33100, [?ERRCODE(err331_not_scratch_all)]
							)
					end;
				_ ->
					lib_server_send:send_to_sid(
						Player#player_status.sid, pt_331, 33100, [?ERRCODE(err331_not_scratch_all)]
					)
			end;
		_ ->
			lib_server_send:send_to_sid(
				Player#player_status.sid, pt_331, 33100, [?ERRCODE(err331_act_closed)]
			)
	end,
	{ok, Player}.

%% -------------------------------------------------------------------
%% @doc 抽奖信息 @end
%% -------------------------------------------------------------------
get_draw_info(Player, SubType) ->
	case lib_custom_act_api:is_open_act(?CUSTOM_ACT_TYPE_SCRATCH_CARD, SubType) of
		true ->
			#custom_act_data{act_data = ActData} =
				lib_custom_act_data:custom_act_data(?CUSTOM_ACT_TYPE_SCRATCH_CARD, SubType),
			case ActData of
				#scratch_card_data{draw_list = DrawList, small_pos = SmallPos, score = Score, draw_times = DrawTimes} ->
					{_, DrawReward, _FixDrawReward} = part_scratch_reward(SubType),
					MinDrawBase = get_min_draw_base(DrawReward),
					Min = case SmallPos of
						      0 -> MinDrawBase;
						      _ -> SmallPos
					      end,
					CardList      = pack_draw_list(DrawList, Min),
					NextNeedCost  = get_next_cost_core(SubType, DrawTimes),
					PackBaeReward = pack_draw_base_reward(SubType, Min),
					lib_server_send:send_to_sid(
						Player#player_status.sid, pt_332, 33246, [SubType, CardList, Score, NextNeedCost, PackBaeReward]
					);
				_ ->
					NextNeedCost = get_next_cost_core(SubType, 0),
					{_, DrawReward, _FixDrawReward} = part_scratch_reward(SubType),
					MinDrawBase   = get_min_draw_base(DrawReward),
					PackBaeReward = pack_draw_base_reward(SubType, MinDrawBase),
					lib_server_send:send_to_sid(
						Player#player_status.sid, pt_332, 33246, [SubType, [], 0, NextNeedCost, PackBaeReward]
					)
			end;
		false ->
			lib_server_send:send_to_sid(
				Player#player_status.sid, pt_331, 33100, [?ERRCODE(err331_act_closed)]
			)
	end,
	ok.

%% 打包已经抽了的奖励位置
pack_draw_list(DrawList, SmallPos) ->
	F = fun(GradeId, AccPos) ->
		Pos = max(1, GradeId-SmallPos+1),
		[Pos|lists:delete(Pos, AccPos)]
	    end,
	lists:foldl(F, [], DrawList).

%% 打包抽奖库奖励
pack_draw_base_reward(SubType, SmallPos) ->
	F = fun(GradeId, {Pos, AccReward}) ->
		case lib_custom_act_util:get_act_reward_cfg_info(?CUSTOM_ACT_TYPE_SCRATCH_CARD, SubType, GradeId) of
			#custom_act_reward_cfg{reward = Reward} ->
				PackReward = [{GoodTypeId, Num}||{_, GoodTypeId, Num}<-Reward],
				{Pos + 1, [{Pos, PackReward}|AccReward]};
			_ ->
				{Pos+1, AccReward}
		end end,
	{_, PackReward} = lists:foldl(F, {1, []}, lists:seq(SmallPos, SmallPos+?ALL_DRAW_POS-1)),
	PackReward.

%% -------------------------------------------------------------------
%% @doc 积分抽奖 @end
%% -------------------------------------------------------------------
score_draw(Player, SubType) ->
	#player_status{id = RoleId, figure = Figure} = Player,
	case lib_custom_act_api:is_open_act(?CUSTOM_ACT_TYPE_SCRATCH_CARD, SubType) of
		true ->
			#custom_act_data{act_data = ActData} = CustomActData =
				lib_custom_act_data:custom_act_data(?CUSTOM_ACT_TYPE_SCRATCH_CARD, SubType),
			%% 检查配置
			{CheckCost, CostList} = check_draw_cost(SubType),

			{CheckCostEnough, NeedScore} = check_cost_enough(ActData, CostList),
			{_, DrawReward, FixDrawReward} = part_scratch_reward(SubType),
			if
				CheckCost == false ->
					lib_server_send:send_to_sid(
						Player#player_status.sid, pt_331, 33100, [?ERRCODE(err331_draw_cost_config_err)]
					),
					ok;
				CheckCostEnough == false ->
					lib_server_send:send_to_sid(
						Player#player_status.sid, pt_331, 33100, [?ERRCODE(err331_draw_cost_not_enough)]
					),
					ok;
				true -> % todo:对可以抽取的奖励适当做一些容错
					{NewActData, RandReward, Pos, TvShowList} =
						draw_card_core(SubType, ActData, DrawReward, FixDrawReward, NeedScore),
					NewCustomActData = CustomActData#custom_act_data{act_data = NewActData},
					Produce = #produce{reward = RandReward, type = score_draw},
					{ok, NewPlayer} = lib_goods_api:send_reward_with_mail(Player, Produce, ?MOD_AC_CUSTOM),
					lib_custom_act_data:save_custom_data(RoleId, NewCustomActData),
					TvShowList =/= [] andalso notice_tv(draw, SubType, Figure#figure.name, TvShowList),
					#scratch_card_data{
						draw_list = DrawList, score = NewScore, draw_times = NewDrawTimes, small_pos = NewSmallPos
					} = NewActData,
					NextNeedCost  = get_next_cost_core(SubType, NewDrawTimes),
					PackBaeReward = pack_draw_base_reward(SubType, NewSmallPos),
					CardList = pack_draw_list(DrawList, NewSmallPos),
					lib_server_send:send_to_sid(Player#player_status.sid, pt_332, 33247,
						[?SUCCESS, SubType, CardList, Pos, NewScore, NextNeedCost, PackBaeReward]),
					log_send_goods(NewPlayer, Player, ?CUSTOM_ACT_TYPE_SCRATCH_CARD, SubType, "score_draw", RandReward),
					{ok, NewPlayer}
			end;
		false ->
			lib_server_send:send_to_sid(Player#player_status.sid, pt_331, 33100, [?ERRCODE(err331_act_closed)]),
			ok
	end.

%% ------------------------------ builtin_function ----------------------------
%% @doc 每抽奖一次得1积分,全部刮开可额外获得5积分 @end
scratch_card_core(SubType, ActData, Option, Pos, RewardList) ->
	case ActData of
		#scratch_card_data{
			card_list = HasScratchL
			,score    = Score
		} ->
			ActData1 = ActData;
		_ ->
			HasScratchL = [], Score = 0,
			ActData1 = #scratch_card_data{}
	end,
	case Option of
		?RAND_SCRATCH ->
			HasScratchL1 = [TPos||{TPos, _}<-HasScratchL],
			LeftL = ?SCRATCH_ALL_POS -- HasScratchL1,
			{GradeId, Reward} = urand:rand_with_weight(RewardList),
			case LeftL of
				[] -> % 刮完了,理论上不会发生
					ScratchPos = urand:list_rand(?SCRATCH_ALL_POS),
					NewHasScratchL = [{ScratchPos, GradeId}|lists:keydelete(ScratchPos, 1, HasScratchL)];
				_ ->
					ScratchPos = urand:list_rand(LeftL),
					NewHasScratchL = [{ScratchPos, GradeId}|lists:delete(ScratchPos, HasScratchL)]
			end,
			NewScore = Score + 1,
			Reward1 = [{TGoodsTypeId, TNum}||{_, TGoodsTypeId, TNum}<-Reward],
			PackRewardL = [{ScratchPos, Reward1}],
			IfShow = if_tv_show(SubType, GradeId),
			TvShowList = case IfShow of
				             true -> [GradeId];
				             _ -> []
			             end;
		?FIX_SCRATCH ->
			{GradeId, Reward}  = urand:rand_with_weight(RewardList),
			NewHasScratchL = [{Pos, GradeId}|lists:delete(Pos, HasScratchL)],
			NewScore = Score + 1,
			Reward1 = [{TGoodsTypeId, TNum}||{_, TGoodsTypeId, TNum}<-Reward],
			PackRewardL = [{Pos, Reward1}],
			IfShow = if_tv_show(SubType, GradeId),
			TvShowList = case IfShow of
				             true -> [GradeId];
				             _ -> []
			             end;
		?ALL_SCRATCH ->
			HasScratchL1 = [TPos||{TPos, _}<-HasScratchL],
			LeftL = ?SCRATCH_ALL_POS -- HasScratchL1,
			ScratchNum = length(LeftL),
			F = fun(TPos, {AccCard, AccReward, AccPackReward}) ->
				{TGradId, TReward} = urand:rand_with_weight(RewardList),
				TReward1 = [{TGoodsTypeId, TNum}||{_, TGoodsTypeId, TNum}<-TReward],
				{[{TPos, TGradId}|AccCard], TReward ++ AccReward, [{TPos, TReward1}|AccPackReward]}
			    end,
			{CardList, Reward, PackRewardL} = lists:foldl(F, {[], [], []}, LeftL),
			NewHasScratchL = CardList ++ HasScratchL,
			NewScore  = Score + ScratchNum,
			F1 = fun({_, GradeId}, AccList) ->
				IfShow = if_tv_show(SubType, GradeId),
				case IfShow of
					true -> [GradeId|AccList];
					_ -> AccList
				end end,
			TvShowList = lists:foldl(F1, [], CardList);
		_ -> % 理论上不会发生
			NewHasScratchL = HasScratchL,
			Reward   = [],
			NewScore = Score,
			PackRewardL = [],
			TvShowList = []
	end,
	case length(NewHasScratchL) rem ?SCRATCH_MILL_STONE of
		0 ->
			NewScore1 = NewScore + ?SCRATCH_CARD_EXTRA_SCORE;
		_ ->
			NewScore1 = NewScore
	end,
	%% 缓存传闻
	OldCacheTvList = proc_get_tv_list(),
	case Option of
		?FIX_SCRATCH when TvShowList =/= [] ->
			CacheTvList = [{Pos, TvShowList}|lists:keydelete(Pos, 1, OldCacheTvList)];
		_ ->
			CacheTvList = OldCacheTvList
	end,
	proc_put_tv_list(CacheTvList),
	NewActData = ActData1#scratch_card_data{
		card_list = NewHasScratchL
		,score    = NewScore1
	},
	{NewActData, Reward, PackRewardL, TvShowList}.

%% @doc 如果库抽完了进行下一个库 @end
draw_card_core(SubType, ActData, DrawReward, FixDrawReward, NeedScore) ->
	#scratch_card_data{
		draw_list  = DrawList
		,score     = Score
		,small_pos = SmallPos
		,draw_times= DrawTimes
	} = ActData,
	%% 顺序库的开始
	MinDrawBase = get_min_draw_base(DrawReward),
	%% 顺序库的结束
	MaxDrawBase = get_max_draw_base(DrawReward),
	%% 固定库的开始
	FixMinDrawBase = get_min_draw_base(FixDrawReward),
	%% 矫正small_pos
	Min = case SmallPos of
			  0 -> MinDrawBase;
			  _ -> SmallPos
	      end,
	Max = Min + ?ALL_DRAW_POS - 1,
	AllGrade  = lists:seq(Min, Max),
	LeftGrade = AllGrade -- DrawList,
	case SmallPos >= FixMinDrawBase of
		true -> SelectReward = FixDrawReward;
		_    -> SelectReward = DrawReward
	end,
	CanDrawReward = [{Weight, {GradeId, Reward}}||
		{Weight, {GradeId, Reward}}<-SelectReward, lists:member(GradeId, LeftGrade)
	],
	{RandGradeId, RandReward} = urand:rand_with_weight(CanDrawReward),
	DrawList1 = [RandGradeId|lists:delete(RandGradeId, DrawList)],
	%% 判断组合库的是否已将抽取完
	case SmallPos > MaxDrawBase of
		true ->
			%% 固定库循环抽奖
			% RewardLen = length(FixDrawReward),
			case length(DrawList1) >= ?ALL_DRAW_POS of
				true -> NewDrawList = [];
				_    -> NewDrawList = DrawList1
			end,
			NewSmallPos = SmallPos;
		_ ->
			case length(DrawList1) of
				?ALL_DRAW_POS ->
					SmallPos1 = Min + ?ALL_DRAW_POS,
					%% 如果已经抽完了所有顺序库
					NewSmallPos =
					case SmallPos1 > MaxDrawBase of
						true -> FixMinDrawBase;
						_ -> SmallPos1
					end,
					NewDrawList = [];
				_ ->
					NewSmallPos = Min,
					NewDrawList = DrawList1
			end
	end,
	LeftScore = max(0, Score-NeedScore),
	IfShow = if_tv_show(SubType, RandGradeId),
	TvShowList = case IfShow of
		             true -> [RandGradeId];
		             _ -> []
	             end,
	NewActData = ActData#scratch_card_data{
		draw_list   = NewDrawList
		,score      = LeftScore
		,small_pos  = NewSmallPos
		,draw_times = DrawTimes + 1
	},
	Pos = RandGradeId - Min + 1,
	{NewActData, RandReward, Pos, TvShowList}.

get_max_draw_base(DrawReward) ->
	case DrawReward of
		[{_, {_TGradeId, _}}|_] ->
			GradeIdL = [GradeId||{_Weight, {GradeId, _Reward}}<-DrawReward],
			[SmallGradeId|_] = lists:sort(GradeIdL),
			BaseNum = umath:ceil(length(DrawReward) / ?ALL_DRAW_POS),
			MaxBaseId = SmallGradeId + max(0, BaseNum-1) * ?ALL_DRAW_POS;
		_ ->
			MaxBaseId = 1
	end,
	MaxBaseId.

get_min_draw_base(DrawReward) ->
	case DrawReward of
		[{_, {_TGradeId, _}}|_] ->
			GradeIdL = [GradeId||{_Weight, {GradeId, _Reward}}<-DrawReward],
			[SmallGradeId|_] = lists:sort(GradeIdL);
		_ ->
			SmallGradeId = 1
	end,
	SmallGradeId.

%% 获取下次抽奖扣除的积分(兼容配置错误,保底显示扣1积分)
get_next_cost_core(SubType, DrawTimes) ->
	case lib_custom_act_util:get_act_cfg_info(?CUSTOM_ACT_TYPE_SCRATCH_CARD, SubType) of
		#custom_act_cfg{condition = Condition} ->
			case lists:keyfind(score_cost, 1, Condition) of
				{_, CostList} ->
					NewTimes  = DrawTimes + 1,
					NeedScore =
						case NewTimes > length(CostList) of
							true -> lists:last(CostList);
							_ -> lists:nth(NewTimes, CostList)
						end;
				_ ->
					NeedScore = 1
			end;
		_ ->
			NeedScore = 1
	end,
	NeedScore.

%% 记录日志
log_send_goods(NewPlayer, Player, Type, SubType, RewardType, Reward) ->
	#player_status{id = RoleId, figure = Figure, gold = Gold, bgold = BGold} = Player,
	#player_status{gold = NewGold, bgold = NewBGold} = NewPlayer,
	#figure{vip = Vip, lv = Lv} = Figure,
	WorldLv = util:get_world_lv(),
	lib_log_api:log_custom_act_reward(RoleId, Type, SubType,
		0, WorldLv, Reward, RewardType, Vip, Lv, Gold, NewGold, BGold, NewBGold, utime:unixtime()
	),
	ok.

%% -------------------------------------------------------------
%% 刮卡 & 抽奖相关检查
%% -------------------------------------------------------------
%% 检查消耗配置
check_scratch_cost(SubType) ->
	case lib_custom_act_util:get_act_cfg_info(?CUSTOM_ACT_TYPE_SCRATCH_CARD, SubType) of
		#custom_act_cfg{condition = Condition} ->
			case lists:keyfind(scratch_card_cost, 1, Condition) of
				{_, [{_GoodsType, _GoodTypeId, _Num}] = Cost} ->
					{true, Cost};
				_ ->
					{false, []}
			end;
		_ ->
			{false, []}
	end.

%% 检查是否全部刮完
check_has_scratch_all(ActData) ->
	HasScratch = case ActData of
		             #scratch_card_data{card_list = CardList} -> CardList;
		             _ -> []
	             end,
	case length(HasScratch) == ?SCRATCH_MILL_STONE of
		true -> false;
		_    -> true
	end.

%% 检查刮奖选择
check_scratch_option(Option) ->
	lists:member(Option, ?SCRATCH_OPTIONS).

%% 检查刮奖位置
check_scratch_pos(ActData, Option, Pos) ->
	HasScratch = case ActData of
					 #scratch_card_data{card_list = CardList} -> CardList;
					 _ -> []
	             end,
	case Option of
		?FIX_SCRATCH when HasScratch == [] ->
			lists:member(Pos, ?SCRATCH_ALL_POS);
		?FIX_SCRATCH ->
			case lists:keyfind(Pos, 1, HasScratch) of
				{_, _} -> false;
				_ ->
					lists:member(Pos, ?SCRATCH_ALL_POS)
			end;
		_ ->
			true
	end.

%% 检查刮奖材料 Cost:单抽消耗的材料
check_material_enough(Player, Option, ActData, Cost, BuffFree, BuffCount) ->
	ActData1 = case is_record(ActData, scratch_card_data) of
				   true -> ActData;
				   _ -> #scratch_card_data{}
	           end,
	HasScratchL  = ActData1#scratch_card_data.card_list,
	HasScratchL1 = [TPos||{TPos, _}<-HasScratchL],
	LeftL = ?SCRATCH_ALL_POS -- HasScratchL1,
	ScratchNum = length(LeftL),
	%% 先扣除免费次数
	case Option of
		?ALL_SCRATCH -> ScratchNum1 = max(0, ScratchNum - BuffFree);
		_ -> ScratchNum1 = max(0, 1 - BuffFree)
	end,
	case ScratchNum1 of
		0 -> {true, [], 1, 0};
		_ ->
			#player_status{gold = Gold, bgold = BGold} = Player,
			case Cost of
				[{GoodsType, GoodsTypeId, Num}|_] ->
					[{_, HasNum}] = lib_goods_api:get_goods_num(Player, [GoodsTypeId]),
					NeedMaterial = case BuffCount > 0 of
						               true ->
						               	   DisC = custom_unite_buff:check_discount(Player,activity_discount),
							               Discount = util:floor(Num*min(BuffCount, ScratchNum1)*DisC),
							               NotDiscount = Num * max(0, ScratchNum1-BuffCount),
							               Discount + NotDiscount;
									   _ ->
										   Num*ScratchNum1
					               end,
					NeedMaterial1 = max(1, NeedMaterial),
					case HasNum >= NeedMaterial1 of
						true ->
							Cost1 = [{GoodsType, GoodsTypeId, NeedMaterial1}],
							{true, Cost1, BuffFree, min(BuffCount, ScratchNum1)};
						_ ->
							case data_goods_price:get_goods_price(GoodsTypeId) of
								#goods_price{price_type = PriceType, price = Price} ->
									NeedPrice = Price * NeedMaterial1,
									HasPrice  = Price * HasNum,
									NeedPriceC = NeedPrice - HasPrice,
									NeedPriceC1 = max(1, NeedPriceC),
									case HasNum > 0 of
										true ->
											TrueCost = [{GoodsType, GoodsTypeId, HasNum}, {PriceType, 0, NeedPriceC1}];
										_ ->
											TrueCost = [{PriceType, 0, NeedPriceC1}]
									end,
									IsEnough =
										case PriceType of
											?TYPE_GOLD  -> Gold  >= NeedPriceC1;
											?TYPE_BGOLD -> BGold >= NeedPriceC1;
											_ -> false
										end,
									{IsEnough, TrueCost, BuffFree, min(ScratchNum1, BuffCount)};
								_ ->
									{false, Cost, 0, 0}
							end
					end;
				_ ->
					{false, Cost, 0, 0}
			end
	end.

%% 检查抽奖消耗配置
check_draw_cost(SubType) ->
	case lib_custom_act_util:get_act_cfg_info(?CUSTOM_ACT_TYPE_SCRATCH_CARD, SubType) of
		#custom_act_cfg{condition = Condition} ->
			case lists:keyfind(score_cost, 1, Condition) of
				{_, CostList} -> {true, CostList};
				_ -> {false, []}
			end;
		_ ->
			{false, []}
	end.

%% 检查积分是否足够(兼容配置错误,至少扣1积分)
check_cost_enough(ActData, CostList) ->
	case ActData of
		#scratch_card_data{score = Score, draw_times = DrawTimes} ->
			NewTimes = DrawTimes + 1,
			NeedScore =
			case NewTimes > length(CostList) of
				true -> lists:last(CostList);
				_ -> lists:nth(NewTimes, CostList)
			end,
			case Score >= NeedScore of
				true -> {true, max(1, NeedScore)};
				_ -> {false, 1}
			end;
		_ -> {false, 1}
	end.

%% -------------------------------------------------------------
%% 根据配置condition里的type将奖励分类
%% return - RewardList = [{weight,{grade,reward}}]
part_scratch_reward(SubType) ->
	RewardList = lib_custom_act_util:get_act_reward_grade_list(?CUSTOM_ACT_TYPE_SCRATCH_CARD, SubType),
	PartFun = fun(GradeId, {ScratchReward, DrawReward, DrawFixReward}) ->
		case lib_custom_act_util:get_act_reward_cfg_info(?CUSTOM_ACT_TYPE_SCRATCH_CARD, SubType, GradeId) of
			#custom_act_reward_cfg{condition = Condition, reward = Reward} ->
				case lists:keyfind(type, 1, Condition) of
					{type, Type} ->
						case lists:keyfind(weight, 1, Condition) of
							{weight, Weight} ->
								case Type of
									1 ->
										NewScratchReward = [{Weight, {GradeId, Reward}}|ScratchReward],
										{NewScratchReward, DrawReward, DrawFixReward};
									2 ->
										NewDrawReward = [{Weight, {GradeId, Reward}}|DrawReward],
										{ScratchReward, NewDrawReward, DrawFixReward};
									3 ->
										NewDrawFixReward = [{Weight, {GradeId, Reward}}|DrawFixReward],
										{ScratchReward, DrawReward, NewDrawFixReward};
									_ ->
										{ScratchReward, DrawReward, DrawFixReward}
								end;
							_ ->
								{ScratchReward, DrawReward, DrawFixReward}
						end;
					_ ->
						{ScratchReward, DrawReward, DrawFixReward}
				end;
			_ ->
				{ScratchReward, DrawReward, DrawFixReward}
		end
	end,
	lists:foldl(PartFun, {[], [], []}, RewardList).

%% 判断是否进行传闻
if_tv_show(SubType, GradeId) ->
	case lib_custom_act_util:get_act_reward_cfg_info(?CUSTOM_ACT_TYPE_SCRATCH_CARD, SubType, GradeId) of
		#custom_act_reward_cfg{condition = Condition} ->
			case lists:keyfind(tv_show, 1, Condition) of
				{_, 1} -> true;
				_ -> false
			end;
		_ ->
			false
	end.

%% 发送传闻
notice_tv(TvType, SubType, RoleName, ShowGradeList) ->
	Fun = fun(GradeId, BinData) ->
		case lib_custom_act_util:get_act_reward_cfg_info(?CUSTOM_ACT_TYPE_SCRATCH_CARD, SubType, GradeId) of
			#custom_act_reward_cfg{reward = [{_, GoodTypeId, Num}]} ->
				case TvType of
					scratch -> Bin = lib_chat:make_tv(?MOD_AC_CUSTOM, 23, [RoleName, GoodTypeId, Num]);
					draw    -> Bin = lib_chat:make_tv(?MOD_AC_CUSTOM, 24, [RoleName, GoodTypeId, Num])
				end,
				<<Bin/binary, BinData/binary>>;
			_ ->
				BinData
		end end,
	SumBinData = lists:foldl(Fun, <<>>, ShowGradeList),
	lib_server_send:send_to_all(SumBinData),
	ok.

%% ------------------------------- gm --------------------------------
gm_add_scratch_score(Player, SubType, AddScore) ->
	case lib_custom_act_api:is_open_act(?CUSTOM_ACT_TYPE_SCRATCH_CARD, SubType) of
		true ->
			#custom_act_data{act_data = ActData} = CustomActData =
				lib_custom_act_data:custom_act_data(?CUSTOM_ACT_TYPE_SCRATCH_CARD, SubType),
			case ActData of
				#scratch_card_data{
					draw_list  = CardList
					,small_pos = SmallPos
					,score = Score
				} = ActData ->
					NewScore = Score + AddScore,
					NewActData = ActData#scratch_card_data{score = NewScore},
					NewCustomActData = CustomActData#custom_act_data{act_data = NewActData},
					lib_custom_act_data:save_custom_data(Player#player_status.id, NewCustomActData),
					lib_server_send:send_to_sid(
						Player#player_status.sid, pt_332, 33246, [SubType, CardList, SmallPos, NewScore]
					);
				_ ->
					NewActData = #scratch_card_data{score = AddScore},
					NewCustomActData = CustomActData#custom_act_data{act_data = NewActData},
					lib_custom_act_data:save_custom_data(Player#player_status.id, NewCustomActData),
					lib_server_send:send_to_sid(
						Player#player_status.sid, pt_332, 33246, [SubType, [], 0, AddScore]
					)
			end,
			ok;
		_ ->
			ignore
	end.