%%-----------------------------------------------------------------------------
%% @Module  :       lib_custom_act_do_normal
%% @Author  :       Ywf
%% @Email   :       349162727@qq.com
%% @Created :       2019-05-08
%% @Description:	定制活动一些通用处理（活动逻辑较少不开新模块时可走这里）
%%                  本模块导出的函数禁止本模块内部直接调用，请走dispatcher分发器
%%-----------------------------------------------------------------------------
-module (lib_custom_act_do_normal).

-include("custom_act.hrl").
-include("def_module.hrl").
-include("common.hrl").
-include("server.hrl").
-include("figure.hrl").
-include("errcode.hrl").
-include("def_fun.hrl").
-include("guild.hrl").
-include("def_daily.hrl").
-include("consume_rank_act.hrl").
-include("goods.hrl").
-include("predefine.hrl").
-include("def_goods.hrl").

-export ([ %% lib_custom_act_check
    check_cfg/1,                        %% 开启活动检测配置是否正确
    check_receive_reward_conditions/3,  %% 检测领取奖励是否符合条件
    check_reward_receive_times/3,       %% 检测领取奖励次数
    check_receive_reward_special/3      %% 领奖特殊检测（与conditions检测不同）
    ]).

-export ([ %% lib_custom_act
%% ----------------- 活动开启 -------------------
    notify_other_module/5,              %% 开启活动通知其他模块
    do_timer_check_other/2,             %% 开启活动额外检测
%% ----------------- 领奖状态计算 -------------------
    ask_reward_status/3,
    ask_act_red_gift_status/3,
    send_reward_status/2,               %% 发送奖励领取状态
    get_grade_status/4,                 %% 取得活动某档次状态（send_reward_status中的部分数据）
    count_reward_progress/4,            %% 计算奖励进度
    count_common_progress/2,            %% 计算通用奖励进度
    count_reward_status/4,              %% 计算可领取状态
    count_receive_times/3,              %% 计算已领取次数
%% ----------------- 领奖相关 -------------------
    receive_reward/4,                   %% 领取奖励
    receive_red_gift_reward/4,          %% 领取红点礼包奖励
    do_receive_reward/4,                %% 发奖励
    update_receive_times_normal/5,      %% 更新领取次数
    get_extra_log/1                     %% 获取领取奖励日志额外数据
    , auto_receive_reward/3
    ]).

-export ([ %% lib_custom_act_api
%% ----------------- 发送未领取奖励 --------------------------
    check_has_rewards_for_forget/4,     %% 检测活动结束时是否有忘记领取的奖励
    check_has_rewards_for_merge/4,      %% 检测合服时是否有未领取的奖励
    get_act_roles/1,                    %% 获取参与活动的玩家
    make_role_info_for_check/3,         %% 获取玩家定制活动的检测数据
    calc_got_reward_times/3,            %% 计算获奖次数
%% ----------------- 0点更新数据 -----------------------------
    is_need_daily_update/2              %% 用于判断该活动是否需要0点更新
    ]).

-export ([
    kf_notify_other_module/4,           %% 跨服中心起来后提醒模块处理数据
    player_daily_update_12/1,           %% 每日0点更新领奖数据
    count_act_reward_other/2
    ]).


%% ------------------------------ lib_custom_act_check ----------------------------
%% 活动开启前做配置检测
check_cfg(#custom_act_cfg{type = ?CUSTOM_ACT_TYPE_SMASHED_EGG, condition = Condition}) ->
    case lib_custom_act_check:check_act_condtion([role_lv, free_refresh_times, smashed_times_lim, all_use_num, refresh_cost, smash_goods, smash_goods_num], Condition) of
        false -> false;
        _ -> true
    end;
check_cfg(_ActCfg) -> true.

%% 判断领取奖励条件是否达标
%% 累充
check_receive_reward_conditions(Player, #act_info{key = {Type, _}, stime = Stime, etime = ETime}, RwCfg)
    when Type =:= ?CUSTOM_ACT_TYPE_RECHARGE
    orelse Type =:= ?CUSTOM_ACT_THEME_FIRST_RECHARGE ->
    #custom_act_reward_cfg{condition = Conditions} = RwCfg,
    case lists:keyfind(gold, 1, Conditions) of
        {gold, Value} ->
            PlayerId = if is_record(Player, player_status) -> Player#player_status.id; true -> Player end,
            X = lib_recharge_data:get_my_recharge_between(PlayerId, Stime, ETime),
            ?IF(X >= Value, true, {false, ?ERRCODE(err331_act_can_not_get)});
        _ -> {false, ?ERRCODE(err331_no_act_reward_cfg)}
    end;
%% 充值有礼
check_receive_reward_conditions(Player, #act_info{key = {?CUSTOM_ACT_TYPE_RECHARGE_GIFT, _}, stime = Stime}, RwCfg) ->
    #custom_act_reward_cfg{condition = Conditions} = RwCfg,
    HistoryList = lib_recharge_data:get_my_daily_recharge_summaries(Player#player_status.id, Stime),
    X = lists:sum([G || {_, {G, _}} <- HistoryList]),
    case lists:keyfind(gold, 1, Conditions) of
        {gold, Value} -> ?IF(X >= Value, true, {false, ?ERRCODE(err331_act_can_not_get)});
        _ -> ?IF(X > 0, true, {false, ?ERRCODE(err331_no_act_reward_cfg)})
    end;
%% 消费活动
check_receive_reward_conditions(Player, #act_info{key = {?CUSTOM_ACT_TYPE_CONSUME, _}, stime = Stime, etime = Etime}, RwCfg) ->
    #custom_act_reward_cfg{condition = Conditions} = RwCfg,
    case lists:keyfind(money_type, 1, Conditions) of
        {money_type, MoneyType, Value} ->
            PlayerId = if is_record(Player, player_status) -> Player#player_status.id; true -> Player end,
            ConsumeValue = if
                MoneyType == gold ->
                    lib_consume_data:get_gold_consume_between(PlayerId, Stime, Etime);
                true -> 0
            end,
            ?IF(ConsumeValue >= Value, true, {false, ?ERRCODE(err331_act_can_not_get)});
        _ -> {false, ?ERRCODE(err_config)}
    end;
%% 充值榜
check_receive_reward_conditions(Player, #act_info{key = {?CUSTOM_ACT_TYPE_RECHARGE_RANK, SubType}, stime = Stime, etime = Etime}, RwCfg) ->
    #custom_act_reward_cfg{grade = GradeId} = RwCfg,
    case lib_recharge_data:get_my_recharge_between(Player#player_status.id, max(Stime, util:get_merge_time()), Etime) of
        RechargeNum when RechargeNum > 0 ->
            case lib_consume_rank_act:is_participate_reward(?RANK_TYPE_RECHARGE, SubType, GradeId, RechargeNum) of
                true ->
                    true;
                _ ->
                    {false, ?ERRCODE(err331_act_can_not_get)}
            end;
        _ -> {false, ?ERRCODE(err331_act_can_not_get)}
    end;
%% 消费榜
check_receive_reward_conditions(Player, #act_info{key = {?CUSTOM_ACT_TYPE_CONSUME_RANK, SubType}, stime = Stime, etime = Etime}, RwCfg) ->
    #custom_act_reward_cfg{grade = GradeId} = RwCfg,
    case lib_consume_data:get_gold_consume_between(Player#player_status.id, max(Stime, util:get_merge_time()), Etime) of
        ConsumeNum when ConsumeNum > 0 ->
            case lib_consume_rank_act:is_participate_reward(?RANK_TYPE_CONSUME, SubType, GradeId, ConsumeNum) of
                true ->
                    true;
                _ ->
                    {false, ?ERRCODE(err331_act_can_not_get)}
            end;
        _ -> {false, ?ERRCODE(err331_act_can_not_get)}
    end;
%% 每日累充(每日重置版)
check_receive_reward_conditions(Player, #act_info{key = {?CUSTOM_ACT_TYPE_DAILY_RECHARGE_EX, _SubType}}, RwCfg) ->
    #custom_act_reward_cfg{condition = Condition} = RwCfg,
    case lib_custom_act_check:check_act_condtion([gold], Condition) of
        [NeedGold] ->
            PlayerId = if is_record(Player, player_status) -> Player#player_status.id; true -> Player end,
            RechargeGold = lib_recharge_api:get_today_pay_gold(PlayerId),
            ?IF(RechargeGold >= NeedGold, true, {false, ?ERRCODE(err331_act_can_not_get)});
        _ -> {false, ?ERRCODE(err_config)}
    end;
%% 通用
check_receive_reward_conditions(_Player, _ActInfo, _RwCfg) -> true.

%% 领奖特殊检测（与conditions检测不同）
check_receive_reward_special(Player, #act_info{key = {?CUSTOM_ACT_TYPE_CONSUME, _}} = ActInfo, RewardCfg) ->
    case lib_custom_act_check:check_receive_reward_conditions(Player, ActInfo, RewardCfg) of
        true ->
            RewardList = lib_custom_act_util:count_act_reward(Player, ActInfo, RewardCfg),
            Len = length(RewardList),
            Cells = lib_goods_api:get_cell_num(Player),
            case Cells >= Len of
                true ->
                    {true, RewardList};
                false ->
                    {false, ?ERRCODE(err151_no_null_cells)}
            end;
        {false, Errcode} ->
            {false, Errcode}
    end;
check_receive_reward_special(Player, ActInfo, RewardCfg) ->
    case lib_custom_act_check:check_receive_reward_conditions(Player, ActInfo, RewardCfg) of
        true ->
            RewardList = lib_custom_act_util:count_act_reward(Player, ActInfo, RewardCfg),
            case lib_goods_api:can_give_goods(Player, RewardList) of
                true ->
                    {true, RewardList};
                _ ->
                    {false, ?ERRCODE(err150_no_cell)}
            end;
        {false, Errcode} ->
            {false, Errcode}
    end.


%% ----------------------------- lib_custom_act --------------------------------------
%% 活动状态改变时的特殊处理
%%--------------------------------------------------
%% %% 通知其他功能模块定制活动的开启状态
%% @param  ActStatus CUSTOM_ACT_STATUS_CLOSE | CUSTOM_ACT_STATUS_OPEN | CUSTOM_ACT_STATUS_MANUAL_CLOSE
%% 注:CUSTOM_ACT_STATUS_MANUAL_CLOSE类型直接清理相关数据即可,不用处理发奖励的逻辑
%% @param  Type      活动主类型
%% @param  SubType   活动子类型
%% @param  Stime     活动开始时间 活动开始时Stime的值不一定就是当前时间
%% @param  Etime     活动结束时间 活动结束时Etime的值不一定就是当前时间
%% @return           description
%%--------------------------------------------------
notify_other_module(ActStatus, _IsKfActType, #act_info{key = {Type, SubType}} = ActInfo, _Stime, _Etime) ->
    case ActStatus of
        ?CUSTOM_ACT_STATUS_OPEN ->
            lib_custom_act:broadcast_act_info(?CUSTOM_ACT_STATUS_OPEN, [ActInfo]),
            case Type of
                ?CUSTOM_ACT_TYPE_CLOUD_BUY ->
                    mod_cloud_buy_mgr:act_start(SubType);
                ?CUSTOM_ACT_TYPE_SUPPLICATION ->
                    mod_local_supplication:act_start(SubType);
                ?CUSTOM_ACT_TYPE_BOSS ->
                    act_boss_mgr:act_boss_begin(SubType);
                ?CUSTOM_ACT_TYPE_PRINTER_DRAW ->
                    printer_draw:act_start(ActInfo);
                ?CUSTOM_ACT_TYPE_SMALL_RECHARGE->
                    custom_act_small_recharge:notify_other_module(ActStatus,ActInfo);
                _ -> skip
            end;
        ?CUSTOM_ACT_STATUS_CLOSE ->
            lib_custom_act:broadcast_act_info(?CUSTOM_ACT_STATUS_CLOSE, [ActInfo]),
            case Type of
                ?CUSTOM_ACT_TYPE_SMASHED_EGG ->
                    mod_smashed_egg:act_end(ActStatus, ActInfo);
                ?CUSTOM_ACT_TYPE_PERFECT_LOVER ->
                    mod_perfect_lover:act_close(SubType);
                ?CUSTOM_ACT_TYPE_HI_POINT ->
                    mod_hi_point:act_end(ActStatus, ActInfo);
                ?CUSTOM_ACT_TYPE_RED_ENVELOPES ->
                    mod_red_envelopes:clear_act_red_envelopes();
                ?CUSTOM_ACT_TYPE_RECHARGE_RANK ->
                    mod_consume_rank_act:clear_recharge_rank_act(ActStatus, SubType);
                ?CUSTOM_ACT_TYPE_CONSUME_RANK ->
                    mod_consume_rank_act:clear_consume_rank_act(ActStatus, SubType);
                ?CUSTOM_ACT_TYPE_LUCAY_FLOP ->
                    lib_lucky_flop:act_end(ActStatus, ActInfo);
                ?CUSTOM_ACT_TYPE_INVESTMENT ->
                    lib_custom_act_api:send_forgot_rewards(ActInfo);
                ?CUSTOM_ACT_TYPE_RECHARGE_CONSUME ->
                    lib_custom_act_api:send_forgot_rewards(ActInfo);
                ?CUSTOM_ACT_TYPE_REPEAT_RECHARGE_REWARD ->
                    lib_custom_act_api:send_forgot_rewards(ActInfo);
                ?CUSTOM_ACT_TYPE_CONSUME ->
                    lib_custom_act_api:send_forgot_rewards(ActInfo);
                ?CUSTOM_ACT_TYPE_GROWTH_SCORE ->
                    mod_growth_score:act_end(SubType);
                ?CUSTOM_ACT_TYPE_JOY_WISH ->
                    lib_joy_wish_act:act_end(Type, SubType);
                ?CUSTOM_ACT_TYPE_VIP_BAG_ONSALE ->
                    lib_vip_bag_onsale:act_end(Type, SubType);
                ?CUSTOM_ACT_TYPE_DAILY_CHARGE_CONSUME ->
                    custom_act_pellet:act_end(ActInfo);
                ?CUSTOM_ACT_TYPE_SINGLE_RECHARGE ->
                    custom_act_single_recharge:act_end(ActInfo);
                ?CUSTOM_ACT_TYPE_ADVENTURE_ROLE ->
                    custom_act_adventure:act_end(ActInfo);
                ?CUSTOM_ACT_TYPE_BOSS ->
                    act_boss_mgr:act_boss_end(SubType);
                ?CUSTOM_ACT_TYPE_PERMIT_ACTIVE ->
                    permit_active:act_end(ActInfo);
                ?CUSTOM_ACT_TYPE_GREAT_REWARD ->
                    lib_great_rewards:act_end(ActInfo);
                ?CUSTOM_ACT_TYPE_PRINTER_DRAW ->
                    printer_draw:act_end(ActInfo, ActStatus);
                ?CUSTOM_ACT_TYPE_TURNTABLE ->
                    custom_act_turntable:act_end(ActInfo);
                ?CUSTOM_ACT_TYPE_SAKURA_GIFT ->
                    sakura_gift:act_end(SubType);
                _ -> skip
            end;
        ?CUSTOM_ACT_STATUS_MANUAL_CLOSE ->
            lib_custom_act:broadcast_act_info(?CUSTOM_ACT_STATUS_MANUAL_CLOSE, [ActInfo]),
            case Type of
                ?CUSTOM_ACT_TYPE_SMASHED_EGG ->
                    mod_smashed_egg:act_end(ActStatus, ActInfo);
                ?CUSTOM_ACT_TYPE_HI_POINT ->
                    mod_hi_point:act_end(ActStatus, ActInfo);
                ?CUSTOM_ACT_TYPE_RED_ENVELOPES ->
                    mod_red_envelopes:clear_act_red_envelopes();
                ?CUSTOM_ACT_TYPE_RECHARGE_RANK ->
                    mod_consume_rank_act:clear_recharge_rank_act(ActStatus, SubType);
                ?CUSTOM_ACT_TYPE_CONSUME_RANK ->
                    mod_consume_rank_act:clear_consume_rank_act(ActStatus, SubType);
                ?CUSTOM_ACT_TYPE_LUCAY_FLOP ->
                    lib_lucky_flop:act_end(ActStatus, ActInfo);
                ?CUSTOM_ACT_TYPE_GROWTH_SCORE ->
                    mod_growth_score:act_end(SubType);
                ?CUSTOM_ACT_TYPE_JOY_WISH ->
                    lib_joy_wish_act:act_end(Type, SubType);
                ?CUSTOM_ACT_TYPE_VIP_BAG_ONSALE ->
                    lib_vip_bag_onsale:act_end(Type, SubType);
                ?CUSTOM_ACT_TYPE_DAILY_CHARGE_CONSUME ->
                    custom_act_pellet:act_end(ActInfo);
                ?CUSTOM_ACT_TYPE_SINGLE_RECHARGE ->
                    custom_act_single_recharge:act_end(ActInfo);
                ?CUSTOM_ACT_TYPE_CONSUME ->
                    lib_custom_act_api:send_forgot_rewards(ActInfo);
                ?CUSTOM_ACT_TYPE_ADVENTURE_ROLE ->
                    custom_act_adventure:act_end(ActInfo);
                ?CUSTOM_ACT_TYPE_BOSS ->
                    act_boss_mgr:act_boss_end(SubType);
                ?CUSTOM_ACT_TYPE_PERMIT_ACTIVE ->
                    permit_active:act_end(ActInfo);
                ?CUSTOM_ACT_TYPE_GREAT_REWARD ->
                    lib_great_rewards:act_end(ActInfo);
                ?CUSTOM_ACT_TYPE_PRINTER_DRAW ->
                    printer_draw:act_end(ActInfo, ActStatus);
                ?CUSTOM_ACT_TYPE_TURNTABLE ->
                    custom_act_turntable:act_end(ActInfo);
                ?CUSTOM_ACT_TYPE_SAKURA_GIFT ->
                    sakura_gift:act_end(SubType);
                _ -> skip
            end;
        _ -> skip
    end,
    ok;
%% 跨服类型定制活动如果有开服天数限制，且按固定时间结算，需要各个游戏节点达到开服天数条件时通知跨服中心活动开启/重启
notify_other_module(_ActStatus, _IsKfActType, _ActInfo, _Stime, _Etime) ->
    ok.

%% 特殊活动开启检测
do_timer_check_other(#custom_act_cfg{type = ?CUSTOM_ACT_TYPE_DUN_MUL_DROP} = ActInfo, ArgsMap) ->
    #custom_act_cfg{condition = Condition} = ActInfo,
    %% 特定合服天数的服不会开这个活动
    #{merday := MergeDay} = ArgsMap,
    case lib_custom_act_check:check_act_condtion([filter_merge_day], Condition) of
        [FilterMergeDayL] when is_list(FilterMergeDayL) ->
            not lists:member(MergeDay, FilterMergeDayL);
        _ -> true
    end;
do_timer_check_other(#custom_act_cfg{type = ?CUSTOM_ACT_TYPE_DUN_MUL_EXP} = ActInfo, ArgsMap) ->
    #custom_act_cfg{condition = Condition} = ActInfo,
    %% 特定合服天数的服不会开这个活动
    #{merday := MergeDay} = ArgsMap,
    case lib_custom_act_check:check_act_condtion([filter_merge_day], Condition) of
        [FilterMergeDayL] when is_list(FilterMergeDayL) ->
            not lists:member(MergeDay, FilterMergeDayL);
        _ -> true
    end;
do_timer_check_other(#custom_act_cfg{type = ?CUSTOM_ACT_TYPE_BOSS_DOUBLE} = ActInfo, ArgsMap) ->
    #custom_act_cfg{condition = Condition} = ActInfo,
    %% 特定合服天数的服不会开这个活动
    #{merday := MergeDay} = ArgsMap,
    case lib_custom_act_check:check_act_condtion([filter_merge_day], Condition) of
        [FilterMergeDayL] when is_list(FilterMergeDayL) ->
            not lists:member(MergeDay, FilterMergeDayL);
        _ -> true
    end;
do_timer_check_other(_ActInfo, _ArgsMap) -> true.

%% 请求活动奖励领取状态
ask_reward_status(Player, ActType, SubType) ->
    NowTime = utime:unixtime(),
    case lib_custom_act_util:get_custom_act_open_info(ActType, SubType) of
        #act_info{
            etime = Etime
        } = ActInfo when NowTime < Etime ->
            lib_custom_act:send_reward_status(Player, ActInfo);
        _ ->
            lib_custom_act:send_error_code(Player#player_status.id, ?ERRCODE(err331_act_closed))
    end.

%% 发送奖励领取状态
%% 不允许走通用领奖状态协议的活动类型
send_reward_status(_Player, #act_info{key = {ActType, _}}) when
ActType == ?CUSTOM_ACT_TYPE_DAILY_CHARGE_CYCLE;         %% 每日累充有自己的状态协议
ActType == ?CUSTOM_ACT_TYPE_RUSH_RANK;            %% 开服冲榜有自己的状态协议
ActType == ?CUSTOM_ACT_TYPE_LUCKY_TURNTABLE;      %% 幸运转盘有自己的协议
ActType == ?CUSTOM_ACT_TYPE_RED_ENVELOPES;        %% 活动红包有自己的协议
ActType == ?CUSTOM_ACT_TYPE_DAILY_TARGET;         %% 每日目标有自己的协议
ActType == ?CUSTOM_ACT_TYPE_GROWTH_SCORE ->       %% 活动积分有自己的协议
    skip;

%%%% 嗨点
send_reward_status(Player, #act_info{key = {Type, _}} = ActInfo)
    when Type =:= ?CUSTOM_ACT_TYPE_HI_POINT orelse Type =:= ?CUSTOM_ACT_TYPE_HI_POINT_2->
    mod_hi_point:send_reward_status(Player#player_status.id, ActInfo);
%% 通用
send_reward_status(Player, ActInfo) ->
    #act_info{key = {Type, SubType}} = ActInfo,
    GradeIds = lib_custom_act_util:get_act_reward_grade_list(Type, SubType),
    %% 通用进度，大部分活动是同一个进度
    CommonProgress = lib_custom_act_dispatcher:count_common_progress(Player, ActInfo),
    F = fun(GradeId, Acc) ->
        case lib_custom_act_util:get_act_reward_cfg_info(Type, SubType, GradeId) of
            #custom_act_reward_cfg{
                name      = Name,
                desc      = Desc,
                condition = Condition,
                format    = Format,
                reward    = Reward
            } = RewardCfg ->
                {Progress, Status, ReceiveTimes} = get_grade_status(Player, ActInfo, CommonProgress, RewardCfg),
                ConditionStr = util:term_to_string(Condition),
                RewardStr = util:term_to_string(Reward),
                [{GradeId, Format, Progress, Status, ReceiveTimes, Name, Desc, ConditionStr, RewardStr} | Acc];
            _ -> Acc
        end
    end,
    PackList = lists:foldl(F, [], GradeIds),
    {ok, BinData} = pt_331:write(33104, [Type, SubType, PackList]),
    lib_server_send:send_to_sid(Player#player_status.sid, BinData).

%% 取得活动某档次状态
%% 通用版
-spec get_grade_status(Player, ActInfo, CommonProgress, GradeCfg) ->
    {Progress, Status, ReceiveTimes} | error when
    GradeCfg :: GradeId | RewardCfg,
    Player :: #player_status{}, ActInfo :: #act_info{},
    CommonProgress :: non_neg_integer(), GradeId :: non_neg_integer(),
    RewardCfg :: #custom_act_reward_cfg{},
    Progress :: non_neg_integer(),
    Status :: non_neg_integer(),
    ReceiveTimes :: non_neg_integer().
get_grade_status(Player, ActInfo = #act_info{key = {Type, SubType}}, CommonProgress, GradeId) when is_integer(GradeId) ->
    case lib_custom_act_util:get_act_reward_cfg_info(Type, SubType, GradeId) of
        #custom_act_reward_cfg{} = RewardCfg ->
            get_grade_status(Player, ActInfo, CommonProgress, RewardCfg);
        _ ->
            error
    end;
get_grade_status(Player, ActInfo, CommonProgress, RewardCfg = #custom_act_reward_cfg{}) ->
    %% 计算奖励进度，个别活动不同档次判断不同进度
    Progress = lib_custom_act_dispatcher:count_reward_progress(Player, ActInfo, CommonProgress, RewardCfg),
    %% 计算奖励的已领取次数
    ReceiveTimes = lib_custom_act:count_receive_times(Player, ActInfo, RewardCfg),
    %% 计算奖励的领取状态
    Status = lib_custom_act:count_reward_status(Player, ActInfo, Progress, RewardCfg),
    {Progress, Status, ReceiveTimes}.

%% 计算通用奖励进度
count_common_progress(Player, #act_info{key = {Type, _SubType}, stime = STime, etime = ETime})
    when Type =:= ?CUSTOM_ACT_THEME_FIRST_RECHARGE orelse Type =:= ?CUSTOM_ACT_TYPE_RECHARGE ->
    PlayerId = if is_record(Player, player_status) -> Player#player_status.id; true -> Player end,
    lib_recharge_data:get_my_recharge_between(PlayerId, STime, ETime);
count_common_progress(Player, #act_info{key = {Type, _SubType}, stime = STime, etime = ETime})
    when Type =:= ?CUSTOM_ACT_TYPE_CONSUME ->
    PlayerId = if is_record(Player, player_status) -> Player#player_status.id; true -> Player end,
    lib_consume_data:get_gold_consume_between(PlayerId, STime, ETime);
count_common_progress(_, _) -> 0.

%% 计算奖励相关的达成进度
count_reward_progress(_Player, _ActInfo, CommonProgress, _RewardCfg) -> CommonProgress.

%% 获取红点礼包状态
ask_act_red_gift_status(Player, ActType, SubType) ->
    IsPersonalAct = custom_act_personal:is_personal_act(ActType),
    if
        IsPersonalAct ->
            ask_personal_act_red_gift_status(Player, ActType, SubType);
        true ->
            ask_common_act_red_gift_status(Player, ActType, SubType)
    end.

ask_personal_act_red_gift_status(Player, ActType, SubType) ->
    case custom_act_personal:is_personal_act_open(Player, ActType, SubType) of
        {true, _EndTime} ->
            case custom_act_personal:get_custom_act_personal_open_info(Player, ActType, SubType) of
                #custom_act_personal{
                    red_gift = RedGift
                } ->    
                    do_ask_act_red_gift_status(Player#player_status.sid, RedGift, ActType, SubType);
                _A -> ok
            end;
        _ -> ok
    end.

ask_common_act_red_gift_status(Player, ActType, SubType) ->
    NowTime = utime:unixtime(),
    case lib_custom_act_util:get_custom_act_open_info(ActType, SubType) of
        #act_info{etime = Etime} when NowTime < Etime ->
            #custom_act_data{red_gift = RedGift} = lib_custom_act_data:custom_act_data(ActType, SubType),
            do_ask_act_red_gift_status(Player#player_status.sid, RedGift, ActType, SubType);
        _ -> ok
            % lib_custom_act:send_error_code(Player#player_status.id, ?ERRCODE(err331_act_closed))
    end.

do_ask_act_red_gift_status(Sid, RedGift, ActType, SubType) ->
    Ret = calc_red_gift_condition(ActType, SubType),
    case Ret of
        {red_gift, RewardType, _RewardL} ->
            RewardType1 = calc_red_gift_reward_type(RewardType),
            case lists:keyfind(RewardType1, 1, RedGift) of
                {?ACT_COMMON_GIFT_ONCE, RewardStatus} ->
                    {ok, BinData} = pt_336:write(33611, [ActType, SubType, RewardType1, RewardStatus]),
                    lib_server_send:send_to_sid(Sid, BinData);
                {?ACT_COMMON_GIFT_DAILY, Time} ->
                    case utime:is_today(Time) of
                        true -> {ok, BinData} = pt_336:write(33611, [ActType, SubType, RewardType1, ?ACT_REWARD_HAS_GET, []]);
                        _ ->    {ok, BinData} = pt_336:write(33611, [ActType, SubType, RewardType1, ?ACT_REWARD_CAN_GET, []])
                    end,
                    lib_server_send:send_to_sid(Sid, BinData);
                _A ->
                    if RewardType1 == ?ACT_COMMON_GIFT_ONCE orelse RewardType1 == ?ACT_COMMON_GIFT_DAILY ->
                            {ok, BinData} = pt_336:write(33611, [ActType, SubType, RewardType1, ?ACT_REWARD_CAN_GET, []]),
                            lib_server_send:send_to_sid(Sid, BinData);
                        true -> ok
                    end
            end,
            ok;
        {tab_gift, RewardType, GradeList, _RewardL} ->
            RewardType1 = calc_red_gift_reward_type(RewardType),
            GradeRedGiftList = lists:foldl(fun(GradeId, Acc) -> 
                case lists:keyfind({GradeId, RewardType1}, 1, RedGift) of
                    {{_, ?ACT_COMMON_GIFT_ONCE}, RewardStatus} ->
                        [{GradeId, RewardStatus}|Acc];
                    {{_, ?ACT_COMMON_GIFT_DAILY}, Time} ->
                        case utime:is_today(Time) of
                            true -> [{GradeId, ?ACT_REWARD_HAS_GET}|Acc];
                            _    -> [{GradeId, ?ACT_REWARD_CAN_GET}|Acc]
                        end;
                    _A ->
                        if RewardType1 == ?ACT_COMMON_GIFT_ONCE orelse RewardType1 == ?ACT_COMMON_GIFT_DAILY ->
                                [{GradeId, ?ACT_REWARD_CAN_GET}|Acc];
                            true -> Acc
                        end
                end
            end, [], GradeList),
            {ok, BinData} = pt_336:write(33611, [ActType, SubType, RewardType1, 0, GradeRedGiftList]),
            lib_server_send:send_to_sid(Sid, BinData),
            ok;
        _A ->
            ok
    end.

calc_red_gift_reward_type(day)   -> 
    ?ACT_COMMON_GIFT_DAILY;
calc_red_gift_reward_type(once)  -> 
    ?ACT_COMMON_GIFT_ONCE;
calc_red_gift_reward_type(_)     -> 
    0.

calc_red_gift_condition(ActType, SubType) ->
    RedGiftCons = [red_gift, tab_gift],
    case lib_custom_act_util:get_act_cfg_info(ActType, SubType) of
        #custom_act_cfg{condition = Condition} ->
            lists:foldl(fun(ConKey, Acc) -> 
                case lists:keyfind(ConKey, 1, Condition) of
                    false -> Acc;
                    Ret -> Ret
                end
            end, {false, 0, []}, RedGiftCons);
        _ ->
            {false, 0, []}
    end.

%% 计算领取次数
%% 奖励已领取次数
count_receive_times(Player,
    #act_info{key = {Type, SubType}, stime = Stime, etime = Etime},
    #custom_act_reward_cfg{grade = GradeId} ) ->
    case lists:member(Type, [
                ?CUSTOM_ACT_TYPE_ACT_EXCHANGE               % 活动兑换
                ,?CUSTOM_ACT_TYPE_COLWORD                   % 集字活动
                ,?CUSTOM_ACT_TYPE_DAILY_CHARGE_CONSUME      % 每日累充消费
                ,?CUSTOM_ACT_TYPE_SINGLE_RECHARGE           % 每日单笔充值
            ]) of
        true  ->
            UnixDate = utime:unixdate(),
            #custom_act_cfg{condition = Condition} = lib_custom_act_util:get_act_cfg_info(Type, SubType),
            case lists:keyfind(clear_type, 1, Condition) of
                {_, ClearType} ->
                    RewardMap = Player#player_status.status_custom_act#status_custom_act.reward_map,
                    case maps:get({Type, SubType, GradeId}, RewardMap, []) of
                        #reward_status{utime = Utime, receive_times = ReceiveTimes} ->
                            case ClearType of
                                day -> ?IF(Utime >= UnixDate, ReceiveTimes, 0);
                                _ -> ?IF(Utime >= Stime andalso Utime =< Etime, ReceiveTimes, 0)
                            end;
                        _ -> 0
                    end;
                _ -> 0
            end;
        false ->
            0
    end;
count_receive_times(_Player, _ActInfo, _RewardCfg) -> 0.

%% 计算可领取状态
count_reward_status(_Player, #act_info{key = {?CUSTOM_ACT_TYPE_FLOWER_RANK_LOCAL, _SubType}}, _Progress, _RewardCfg) ->
    ?ACT_REWARD_CAN_NOT_GET; %% 本服鲜花榜
count_reward_status(_Player, #act_info{key = {?CUSTOM_ACT_TYPE_FLOWER_RANK, _SubType}}, _Progress, _RewardCfg) ->
    ?ACT_REWARD_CAN_NOT_GET; %% 鲜花榜
count_reward_status(_Player, #act_info{key = {?CUSTOM_ACT_TYPE_COLWORD, _SubType}}, _Progress, _RewardCfg) ->
    ?ACT_REWARD_CAN_GET; %% 开服集字兑换
count_reward_status(Player, #act_info{key = {?CUSTOM_ACT_TYPE_HOPE_GIFT, _SubType}}, _Progress, RewardCfg) ->
    %% 明日之礼领取状态
    case custom_act_hope_gift:receive_status(Player, RewardCfg) of
        true  ->
            ?ACT_REWARD_CAN_GET;
        {false, err331_over_limit_num} ->
            ?ACT_REWARD_HAS_GET;
        _Other ->
            ?ACT_REWARD_CAN_NOT_GET
    end;
count_reward_status(Player, ActInfo, _Progress, RewardCfg) ->
    case lib_custom_act_check:check_reward_receive_times(Player, ActInfo, RewardCfg) of
        false -> ?ACT_REWARD_HAS_GET;
        _ ->
            case lib_custom_act_check:check_receive_reward_conditions(Player, ActInfo, RewardCfg) of
                {false, ErrorCode} ->
                    case ErrorCode =:= ?ERRCODE(err331_act_time_out) of
                        true -> ?ACT_REWARD_TIME_OUT;
                        false -> ?ACT_REWARD_CAN_NOT_GET
                    end;
                _ -> ?ACT_REWARD_CAN_GET
            end
    end.

%% 判断是否已经领过奖了
%% 开启期间只能领一次的活动
check_reward_receive_times(Player, #act_info{key = {ActType, SubType}, stime = Stime, etime = Etime}, #custom_act_reward_cfg{grade = GradeId}) when
    ActType == ?CUSTOM_ACT_TYPE_RECHARGE orelse
    ActType == ?CUSTOM_ACT_THEME_FIRST_RECHARGE orelse
    ActType == ?CUSTOM_ACT_TYPE_RECHARGE_GIFT orelse
    ActType == ?CUSTOM_ACT_TYPE_CONSUME orelse
    ActType == ?CUSTOM_ACT_TYPE_RECHARGE_RANK orelse
    ActType == ?CUSTOM_ACT_TYPE_CONSUME_RANK orelse
    ActType == ?CUSTOM_ACT_TYPE_RECHARGE_CONSUME orelse
    ActType == ?CUSTOM_ACT_TYPE_OVERFLOW_GIFTBAG orelse
    ActType == ?CUSTOM_ACT_TYPE_SPEC_SELL orelse
    ActType == ?CUSTOM_ACT_TYPE_INVESTMENT orelse
    ActType == ?CUSTOM_ACT_TYPE_DAILY_TARGET orelse
    ActType == ?CUSTOM_ACT_TYPE_JOY_WISH orelse
    ActType == ?CUSTOM_ACT_TYPE_VIP_BAG_ONSALE orelse
    ActType == ?CUSTOM_ACT_TYPE_ADVENTURE_ROLE orelse
    ActType == ?CUSTOM_ACT_TYPE_HOPE_GIFT ->
    StatusCustomAct = Player#player_status.status_custom_act,
    RewardMap = StatusCustomAct#status_custom_act.reward_map,
    case maps:get({ActType, SubType, GradeId}, RewardMap, []) of
        #reward_status{utime = Utime, receive_times = ReceiveTimes}
            when Utime >= Stime, Utime =< Etime, ReceiveTimes > 0 ->
            false;
        _ -> {true, 1}
    end;
%% 每日重置版 - 取当天次数状态判断
check_reward_receive_times(#player_status{status_custom_act = #status_custom_act{reward_map = RewardMap}},
    #act_info{key = {Type, SubType}},
    #custom_act_reward_cfg{grade = GradeId
    }) when
    Type == ?CUSTOM_ACT_TYPE_DAILY_RECHARGE_EX orelse
    Type == ?CUSTOM_ACT_TYPE_DAILY_CHARGE_CONSUME ->
        case maps:get({Type, SubType, GradeId}, RewardMap, []) of
        #reward_status{utime = Utime, receive_times = ReceiveTimes} ->
            DateTime = utime:unixdate(),
            ?IF(Utime >= DateTime andalso ReceiveTimes > 0, false, {true, 1});
        _ -> {true, 1}
    end;
%% 重复充值领奖
check_reward_receive_times(#player_status{status_custom_act = #status_custom_act{reward_map = RewardMap}} = PS,
    #act_info{key = {Type = ?CUSTOM_ACT_TYPE_REPEAT_RECHARGE_REWARD, SubType}, stime = STime, etime = ETime}, #custom_act_reward_cfg{grade = GradeId}) ->
    %% 活动期间总领取次数
    AllReceiveTimes = case maps:get({Type, SubType, GradeId}, RewardMap, []) of
                          #reward_status{utime = Utime, receive_times = ReceiveTimes} ->
                              ?IF(Utime >= STime andalso ETime >= Utime, ReceiveTimes, 0);
                          _ -> 0
                      end,
    TotalRecharge = lib_recharge_data:get_my_recharge_between(PS, STime, ETime),
    LeftTimes = case lib_custom_act_util:keyfind_act_condition(Type, SubType, recharge) of
                    {recharge, NeedRecharge} ->
                        AllTimes = TotalRecharge div NeedRecharge,
                        max(0, AllTimes - AllReceiveTimes);
                    _ -> 0
                end,
    ?IF(LeftTimes > 0, {true, AllReceiveTimes + 1}, false);
%% 通用
check_reward_receive_times(_Player, _ActInfo, _RwCfg) -> false.
%%  -------------------------- 领取奖励 ----------------------------------------
%% 不处理的类型
receive_reward(_Player, ActType, _SubType, _GradeId) when
ActType == ?CUSTOM_ACT_TYPE_LUCKY_TURNTABLE;
ActType == ?CUSTOM_ACT_TYPE_PERFECT_LOVER;
ActType == ?CUSTOM_ACT_TYPE_SUPPLICATION;
ActType == ?CUSTOM_ACT_TYPE_RED_ENVELOPES;
ActType == ?CUSTOM_ACT_TYPE_GROWTH_SCORE
    -> skip;
%% 每日累充
receive_reward(Player, ?CUSTOM_ACT_TYPE_DAILY_CHARGE_CYCLE, SubType, GradeId) ->
    case lib_recharge_cumulation:receive_reward(Player, SubType, GradeId) of
        {ok, NewPlayer} ->
            {ok, BinData} = pt_331:write(33105, [?SUCCESS, ?CUSTOM_ACT_TYPE_DAILY_CHARGE_CYCLE, SubType, GradeId]),
            lib_server_send:send_to_sid(NewPlayer#player_status.sid, BinData),
            {ok, NewPlayer};
        {false, ErrCode} ->
            {ok, BinData} = pt_331:write(33100, [ErrCode]),
            lib_server_send:send_to_sid(Player#player_status.sid, BinData)
    end;

%% 嗨点
receive_reward(#player_status{id = RoleId} = Player, Type, SubType, GradeId)
    when Type =:= ?CUSTOM_ACT_TYPE_HI_POINT orelse Type =:= ?CUSTOM_ACT_TYPE_HI_POINT_2->
    case lib_custom_act_util:get_act_reward_cfg_info(Type, SubType, GradeId) of
        #custom_act_reward_cfg{} = RewardCfg ->
            case lists:keyfind({Type, SubType}, #act_info.key, lib_custom_act_util:get_custom_act_open_list()) of
                false -> lib_custom_act:send_error_code(RoleId, ?ERRCODE(err331_act_closed));
                ActInfo ->
                    Reward = lib_custom_act_util:count_act_reward(Player, ActInfo, RewardCfg),
                    case lib_goods_api:can_give_goods(Player, Reward) of
                        true ->
                            mod_hi_point:receive_reward(Player#player_status.id, Type, SubType, GradeId, Reward);
                        _ ->
                            lib_custom_act:send_error_code(RoleId, ?ERRCODE(err150_no_cell))
                    end
            end;
        _ -> lib_custom_act:send_error_code(RoleId, ?ERRCODE(err_config))
    end;
%% 超值礼包|精品特卖
receive_reward(#player_status{sid = Sid} = Player, Type, SubType, GradeId)
    when Type =:= ?CUSTOM_ACT_TYPE_OVERFLOW_GIFTBAG orelse Type =:= ?CUSTOM_ACT_TYPE_SPEC_SELL ->
    case lib_custom_act_util:get_act_reward_cfg_info(Type, SubType, GradeId) of
        #custom_act_reward_cfg{condition = Condition} ->
            [Price] = lib_custom_act_check:check_act_condtion([now_price], Condition),
            case lib_goods_api:check_object_list(Player, Price) of
                true ->
                    case lib_custom_act_check:check_receive_reward(Player, Type, SubType, GradeId) of
                        {true, ActInfo, NewReceiveTimes, RewardList, RewardCfg} ->
                            %% 先更新次数 避免更新次数出问题玩家重复领取
                            Player1 = lib_custom_act:update_receive_times(Player, Type, SubType, GradeId, NewReceiveTimes),
                            case lib_custom_act_dispatcher:do_receive_reward(Player1, ActInfo, RewardList, RewardCfg) of
                                {false, ErrCode} ->
                                    {ok, BinData} = pt_331:write(33105, [ErrCode, Type, SubType, GradeId]),
                                    lib_server_send:send_to_sid(Sid, BinData);
                                Player2 ->
                                    {ok, BinData} = pt_331:write(33105, [?SUCCESS, Type, SubType, GradeId]),
                                    lib_server_send:send_to_sid(Sid, BinData),
                                    {ok, Player2}
                            end;
                        {false, ErrCode} ->
                            {ok, BinData} = pt_331:write(33100, [ErrCode]),
                            lib_server_send:send_to_sid(Sid, BinData)
                    end;
                {false, Err} -> lib_server_send:send_to_sid(Sid, pt_331, 33100, [Err])
            end;
        _ -> lib_server_send:send_to_sid(Sid, pt_331, 33100, [?ERRCODE(err_config)])
    end;
receive_reward(Player, ActType, SubType, GradeId) ->
    case lib_custom_act_check:check_receive_reward(Player, ActType, SubType, GradeId) of
        {true, ActInfo, NewReceiveTimes, RewardList, RewardCfg} ->
            %% 先更新次数 避免更新次数出问题玩家重复领取
            Player1 = lib_custom_act_dispatcher:update_receive_times_normal(Player, ActType, SubType, GradeId, NewReceiveTimes),
            case lib_custom_act_dispatcher:do_receive_reward(Player1, ActInfo, RewardList, RewardCfg) of
                {false, ErrCode} -> NewPlayer = Player1;
                NewPlayer -> ErrCode = ?SUCCESS
            end;
        {false, ErrCode} -> NewPlayer = Player
    end,
    {ok, BinData} = pt_331:write(33105, [ErrCode, ActType, SubType, GradeId]),
    lib_server_send:send_to_sid(Player#player_status.sid, BinData),
    {ok, NewPlayer}.

%%--------------------------------------------------
%% 根据活动类型自己处理各自的领取奖励逻辑
%% @param  Player     #player_status{}
%% @param  ActInfo    #act_info{}
%% @param  RewardList [{ObjectType, Id, Num}]
%% @return            #player_status{}|{false, ErrCode}
%%--------------------------------------------------
%% 超值礼包
do_receive_reward(Player, #act_info{wlv = WLv, key = {?CUSTOM_ACT_TYPE_OVERFLOW_GIFTBAG = Type, SubType}}, RewardList, RewardCfg) ->
    NowTime = utime:unixtime(),
    #player_status{id = RoleId, figure = #figure{lv = Lv, vip = Vip}, overflow_gift = TimeMaps} = Player,
    LvTime = maps:get(SubType, TimeMaps, 0),
    #custom_act_cfg{condition = Conditon0} = lib_custom_act_util:get_act_cfg_info(Type, SubType),
    #custom_act_reward_cfg{grade = Grade, condition = Condition} = RewardCfg,
    [CfgLv, BuyDay] = lib_custom_act_check:check_act_condtion([role_lv, buy_day], Conditon0),
    [Cost] = lib_custom_act_check:check_act_condtion([now_price], Condition),
    case Lv >= CfgLv andalso (NowTime - LvTime) =< (BuyDay * ?ONE_DAY_SECONDS) of
        true ->
            case lib_goods_api:cost_object_list_with_check(Player, Cost, overflow_gift_act, "") of
        {true, NewPs,_} ->
                    case lists:keyfind(gift_id, 1, Condition) of
                        {gift_id, GiftId} ->
                            LastPlayer = lib_goods_api:send_reward(NewPs, [{?TYPE_GOODS, GiftId, 1}], overflow_gift_act, 0),
                            %% 日志
                            lib_log_api:log_custom_act_reward(RoleId, Type, SubType, Grade, WLv, [{?TYPE_GOODS, GiftId, 1}], [],
                                Vip, Lv, Player#player_status.gold, NewPs#player_status.gold, Player#player_status.bgold, NewPs#player_status.bgold, NowTime),
                            LastPlayer;
                        _ ->
                            LastPlayer = lib_goods_api:send_reward(NewPs, RewardList, overflow_gift_act, 0),
                            %% 日志
                            lib_log_api:log_custom_act_reward(RoleId, Type, SubType, Grade, WLv, RewardList, [],
                                Vip, Lv, Player#player_status.gold, LastPlayer#player_status.gold, Player#player_status.bgold, LastPlayer#player_status.bgold, NowTime),
                            LastPlayer
                    end;
                {false, Res, _} -> {false, Res}
            end;
        false -> {false, ?ERRCODE(lv_limit)}
    end;
%% 特卖活动
do_receive_reward(Player, #act_info{wlv = _WLv, key = {?CUSTOM_ACT_TYPE_SPEC_SELL = Type, SubType}}, RewardList, RewardCfg) ->
    NowTime = utime:unixtime(),
    #player_status{id = _RoleId, figure = #figure{lv = Lv}, spec_sell_act= TimeMaps} = Player,
    LvTime = maps:get(SubType, TimeMaps, 0),
    #custom_act_cfg{condition = Conditon0} = lib_custom_act_util:get_act_cfg_info(Type, SubType),
    #custom_act_reward_cfg{grade = _Grade, condition = Condition} = RewardCfg,
    [CfgLv] = lib_custom_act_check:check_act_condtion([role_lv], Conditon0),
    [Cost] = lib_custom_act_check:check_act_condtion([now_price], Condition),
    case lib_custom_act_check:check_act_condtion([buy_day], Conditon0) of %% 有配的情况下 用此天数限制 不配的话整个活动时间能买
        [BuyDay] ->
            CanBuy =Lv >= CfgLv andalso (NowTime - LvTime) =< (BuyDay * ?ONE_DAY_SECONDS);
        _ -> CanBuy =Lv >= CfgLv
    end,
    case CanBuy of
        true ->
            case lib_goods_api:cost_object_list_with_check(Player, Cost, spec_sell_act, "") of
        {true, NewPs,_} ->
                    %% 日志
                    %lib_log_api:log_custom_act_reward(RoleId, Type, SubType, Grade, WLv, RewardList, [], NowTime),
                    lib_goods_api:send_reward(NewPs, RewardList, spec_sell_act, 0);
        {false, Res, _} ->
            {false, Res}
            end;
        false -> {false, ?ERRCODE(lv_limit)}
    end;
%% 通用
do_receive_reward(Player, ActInfo, RewardList, RewardCfg) ->
    case lib_goods_api:can_give_goods(Player, RewardList) of
        true ->
            #act_info{
                wlv = WLv,
                key = {MainActType, SubActType}
            } = ActInfo,
            Produce = #produce{
                type= custom_act,
                subtype = MainActType,
                reward= RewardList,
                remark= util:term_to_string(SubActType)
            },
            #player_status{figure = #figure{lv = Lv, vip = Vip}} = Player,
            Now = utime:unixtime(),
            lib_custom_act_api:log_recharge_consume_act(Player, ActInfo, RewardCfg#custom_act_reward_cfg.grade, 0, RewardList, Now),
            NewPlayer = lib_goods_api:send_reward(Player, Produce),
            %% 日志
            LogExtra = lib_custom_act_dispatcher:get_extra_log(RewardCfg),
            lib_log_api:log_custom_act_reward(Player#player_status.id, MainActType, SubActType, RewardCfg#custom_act_reward_cfg.grade, WLv, RewardList, LogExtra
                , Vip, Lv, Player#player_status.gold, NewPlayer#player_status.gold, Player#player_status.bgold, NewPlayer#player_status.bgold, Now),
            NewPlayer;
        _ ->
            {false, ?ERRCODE(err150_no_cell)}
    end.

%% 更新领取次数 Return：#player_status{}
update_receive_times_normal(Player, Type, SubType, GradeId, NewReceiveTimes) when Type == ?CUSTOM_ACT_TYPE_RECHARGE_RANK; Type == ?CUSTOM_ACT_TYPE_CONSUME_RANK ->
    RankType = ?IF(Type == ?CUSTOM_ACT_TYPE_RECHARGE_RANK, ?RANK_TYPE_RECHARGE, ?RANK_TYPE_CONSUME),
    mod_consume_rank_act:update_participate_award(Player#player_status.id, RankType, SubType, GradeId),
    lib_custom_act:update_receive_times(Player, Type, SubType, GradeId, NewReceiveTimes);
update_receive_times_normal(Player, Type, SubType, GradeId, _NewReceiveTimes) when Type == ?CUSTOM_ACT_TYPE_COLWORD ->
    lib_custom_act_do_colword:update_receive_times(Player, SubType, GradeId);
update_receive_times_normal(Player, Type, SubType, GradeId, NewReceiveTimes) ->
    lib_custom_act:update_receive_times(Player, Type, SubType, GradeId, NewReceiveTimes).

%% 领奖日志额外数据 记录在定制活动奖励日志的'附加记录'字段
get_extra_log(_RwCfg) -> [].


%% 领取红点礼包奖励
receive_red_gift_reward(Player, ActType, SubType, GradeId) ->
    IsPersonalAct = custom_act_personal:is_personal_act(ActType),
    if
        IsPersonalAct ->
            person_act_receive_red_gift_reward(Player, ActType, SubType, GradeId);
        true ->
            common_act_receive_red_gift_reward(Player, ActType, SubType, GradeId)
    end.

person_act_receive_red_gift_reward(Player, ActType, SubType, GradeId) ->
    case custom_act_personal:is_personal_act_open(Player, ActType, SubType) of
        {true, _EndTime} ->
            case custom_act_personal:get_custom_act_personal_open_info(Player, ActType, SubType) of
                CustomActData = #custom_act_personal{
                    red_gift = RedGift
                } ->
                    #player_status{sid = Sid} = Player,
                    RetConditions = calc_red_gift_condition(ActType, SubType),
                    case RetConditions of
                        {false, _, _} ->
                            {ok, BinData} = pt_336:write(33612, [ActType, SubType, GradeId, ?FAIL]),
                            lib_server_send:send_to_sid(Sid, BinData),
                            ok;
                        _A ->
                            case RetConditions of
                                {red_gift, RewardType, RewardL} -> GradeList = [], ok;
                                {tab_gift, RewardType, GradeList, RewardL} -> ok
                            end,
                            IsAccessGrade = 
                            if GradeId == 0 -> true;
                                true -> lists:member(GradeId, GradeList)
                            end,
                            case IsAccessGrade of
                                true ->
                                    Ret = calc_receive_red_gift_ret(RewardType, GradeId, RedGift),
                                    if
                                        not Ret ->
                                            {ok, BinData} = pt_336:write(33612, [ActType, SubType, GradeId, ?ERRCODE(reward_is_got)]),
                                            lib_server_send:send_to_sid(Sid, BinData),
                                            ok;
                                        true ->
                                            NewPlayer = lib_goods_api:send_reward(Player, RewardL, act_red_gift),
                                            {_, NewRedGift} = Ret,
                                            NewCustomActData = CustomActData#custom_act_personal{red_gift = NewRedGift},
                                            #player_status{id = RoleId} = NewPlayer1 = custom_act_personal:save_personal_act(NewPlayer, NewCustomActData),
                                            custom_act_personal:save_personal_act_db(RoleId, NewCustomActData),
                                            {ok, BinData} = pt_336:write(33612, [ActType, SubType, GradeId, ?SUCCESS]),
                                            lib_server_send:send_to_sid(Sid, BinData),
                                            {ok, NewPlayer1}                          
                                    end;
                                false -> ok
                            end
                    end;
                _ -> ok
            end;
        _ -> ok
    end.

common_act_receive_red_gift_reward(Player, ActType, SubType, GradeId) ->
    #player_status{id = RoleId, sid = Sid} = Player,
    NowTime = utime:unixtime(),
    case lib_custom_act_util:get_custom_act_open_info(ActType, SubType) of
        #act_info{etime = Etime} when NowTime < Etime ->
            #custom_act_data{red_gift = RedGift} = CustomActData = lib_custom_act_data:custom_act_data(ActType, SubType),
            ConditionRet = calc_red_gift_condition(ActType, SubType),
            case ConditionRet of
                {false, _, _} ->
                    {ok, BinData} = pt_336:write(33612, [ActType, SubType, GradeId, ?FAIL]),
                    lib_server_send:send_to_sid(Sid, BinData),
                    ok;
                _A ->
                    case ConditionRet of
                        {red_gift, RewardType, RewardL} -> GradeList = [], ok;
                        {tab_gift, RewardType, GradeList, RewardL} -> ok
                    end,
                    IsAccessGrade = 
                    if GradeId == 0 -> true;
                        true -> lists:member(GradeId, GradeList)
                    end,
                    case IsAccessGrade of
                        true ->
                            Ret = calc_receive_red_gift_ret(RewardType, GradeId, RedGift),
                            if
                                not Ret ->
                                    {ok, BinData} = pt_336:write(33612, [ActType, SubType, GradeId, ?ERRCODE(reward_is_got)]),
                                    lib_server_send:send_to_sid(Sid, BinData),
                                    ok;
                                true ->
                                    {_, NewRedGift} = Ret,
                                    NewCustomActData = CustomActData#custom_act_data{red_gift = NewRedGift},
                                    NewPlayer = lib_goods_api:send_reward(Player, RewardL, act_red_gift),
                                    ?IF(NewCustomActData =/= CustomActData, lib_custom_act_data:save_custom_data(RoleId, NewCustomActData), skip),
                                    {ok, BinData} = pt_336:write(33612, [ActType, SubType, GradeId, ?SUCCESS]),
                                    lib_server_send:send_to_sid(Sid, BinData),
                                    {ok, NewPlayer}
                            end;
                        false -> ok
                    end
            end;
        _ ->
            % {ok, BinData} = pt_336:write(33612, [ActType, SubType, GradeId, ?ERRCODE(err331_act_closed)]),
            % lib_server_send:send_to_sid(Sid, BinData),
            ok
    end.

calc_receive_red_gift_ret(RewardType, GradeId, RedGift) ->
    RewardType1 = calc_red_gift_reward_type(RewardType),
    if 
        GradeId == 0 -> Key = RewardType1;
        true -> Key = {GradeId, RewardType1}
    end,
    case lists:keyfind(Key, 1, RedGift) of
        {_, ?ACT_REWARD_CAN_GET} ->
            {true, lists:keystore(Key, 1, RedGift, {Key, ?ACT_REWARD_HAS_GET})};
        {_, ?ACT_REWARD_HAS_GET} ->
            false;
        {_, LastTime} ->
            case utime:is_today(LastTime) of
                false -> {true, lists:keystore(Key, 1, RedGift, {Key, utime:unixtime()})};
                _     -> false
            end;
        _ -> 
            if  RewardType1 == ?ACT_COMMON_GIFT_DAILY -> {true, lists:keystore(Key, 1, RedGift, {Key, utime:unixtime()})};
                RewardType1 == ?ACT_COMMON_GIFT_ONCE  -> {true, lists:keystore(Key, 1, RedGift, {Key, ?ACT_REWARD_HAS_GET})};
                true -> false
            end
    end.

%% ----------------------------------- lib_custom_act_api -----------------------------------
%% 获取参与活动的玩家
get_act_roles(_ActInfo) -> [].

%% 检测活动结束是否有未领取的奖励
check_has_rewards_for_forget(_RoleId, _ActInfo, _RwCfg, _GotTimes) -> false.
%% 检测是否有合服时未领取的奖励
check_has_rewards_for_merge(RoleId, #act_info{key = {Type, SubType}} = ActInfo, RwCfg, 0) when
    Type =:= ?CUSTOM_ACT_TYPE_CONSUME;
    Type =:= ?CUSTOM_ACT_TYPE_RECHARGE_CONSUME;
    Type =:= ?CUSTOM_ACT_TYPE_CONTINUE_CONSUME;
    Type =:= ?CUSTOM_ACT_TYPE_DAILY_RECHARGE_EX;
    Type =:= ?CUSTOM_ACT_TYPE_INVESTMENT
-> %% 只可领取一次的活动
    RoleInfo = lib_custom_act_api:make_role_info_for_check(RoleId, Type, SubType),
    case lib_custom_act_check:check_receive_reward_conditions(RoleInfo, ActInfo, RwCfg) of
        true -> {ok, 1};
        _    -> false
    end;
check_has_rewards_for_merge(_RoleId, _ActInfo, _RwCfg, _GotTimes) -> false.


%% 获取玩家定制活动的检测数据 无固定返回，默认RoleId
make_role_info_for_check(_ActType, _SubType, RoleId) -> RoleId.

%% 计算已领取奖励的次数
%% 每日充值（每日重置版）
calc_got_reward_times(StatusCustomAct, #act_info{key = {?CUSTOM_ACT_TYPE_DAILY_RECHARGE_EX = Type, SubType}}, GradeId) ->
    RewardMap = StatusCustomAct#status_custom_act.reward_map,
    UnixDate = utime:unixdate(),
    case maps:get({Type, SubType, GradeId}, RewardMap, []) of
        #reward_status{utime = Utime, receive_times = ReceiveTimes}
            when Utime >= UnixDate andalso ReceiveTimes > 0 ->
            ReceiveTimes;
        _ ->
            0
    end;
calc_got_reward_times(StatusCustomAct, #act_info{key = {Type, SubType}, stime = Stime, etime = Etime}, GradeId) ->
    RewardMap = StatusCustomAct#status_custom_act.reward_map,
    case maps:get({Type, SubType, GradeId}, RewardMap, []) of
        #reward_status{utime = Utime, receive_times = ReceiveTimes}
            when Utime >= Stime andalso Utime =< Etime andalso ReceiveTimes > 0 ->
            ReceiveTimes;
        _ ->
            0
    end.

%% 用于判断该活动是否需要0点更新
is_need_daily_update(_Player, _ActInfo) -> false.

%% 每日0点更新领奖数据
player_daily_update_12(Player) ->
    CheckTypes = [?CUSTOM_ACT_TYPE_INVESTMENT],
    [
        pp_custom_act:handle(33104, Player, [Type, SubType]) || Type <- CheckTypes,
        #act_info{key = {_, SubType}} = ActInfo <- lib_custom_act_api:get_open_custom_act_infos(Type),
        lib_custom_act_api:is_need_daily_update(Player, ActInfo)
    ],
    ok.


count_act_reward_other(ActInfo, RewardList) when is_record(ActInfo, act_info) ->
    count_act_reward_other(ActInfo, RewardList, []);
count_act_reward_other(_ActInfo, RewardList) -> RewardList.

%% 针对不同的活动对奖励物品进行处理
count_act_reward_other(_ActInfo, [], NewRewardList) ->
	lists:reverse(NewRewardList);
count_act_reward_other(#act_info{key = {Type, _SubType}} = ActInfo, [Reward|RewardList], NewRewardList) when %% 0点刷新的活动
Type == ?CUSTOM_ACT_TYPE_DAILY_ACTIVITY -> %% 每日活跃
    LastRewardList = case Reward of
        {?TYPE_ATTR_GOODS, GoodsId, Num, Attr} ->
            case lists:keyfind(expire_time, 1, Attr) of
                {expire_time, ExpireTime} ->  %% 道具有效时间根据不同活动进行修改
                    NowTime = utime:unixtime(),
                    NextZeroTime = utime:unixdate() + ?ONE_DAY_SECONDS,
                    NewExpireTime = ExpireTime + max(NextZeroTime - NowTime, 0),
                    NewAttr = lists:keystore(expire_time, 1, Attr, {expire_time, NewExpireTime}),
                    [{?TYPE_ATTR_GOODS, GoodsId, Num, NewAttr}|NewRewardList];
                _ ->
                    [{?TYPE_ATTR_GOODS, GoodsId, Num, Attr}|NewRewardList]
              end;
        _ -> [Reward|NewRewardList]
    end,
    count_act_reward_other(ActInfo, RewardList, LastRewardList);
count_act_reward_other(#act_info{etime = ETime} = ActInfo, [Reward|RewardList], NewRewardList) -> %% 按结束时间换算奖励有效期的活动
    LastRewardList = case Reward of
        {?TYPE_ATTR_GOODS, GoodsId, Num, Attr} ->
            case lists:keyfind(expire_time, 1, Attr) of
                {expire_time, ExpireTime} ->  %% 道具有效时间根据不同活动进行修改
                    NowTime = utime:unixtime(),
                    NewExpireTime = ExpireTime + max(ETime - NowTime, 0),
                    NewAttr = lists:keystore(expire_time, 1, Attr, {expire_time, NewExpireTime}),
                    [{?TYPE_ATTR_GOODS, GoodsId, Num, NewAttr}|NewRewardList];
                _ ->
                    [{?TYPE_ATTR_GOODS, GoodsId, Num, Attr}|NewRewardList]
             end;
        _ -> [Reward|NewRewardList]
       end,
    count_act_reward_other(ActInfo, RewardList, LastRewardList).

%% 跨服中心活动状态变化通知
kf_notify_other_module(_ActStatus, #act_info{key = {_Type, _SubType}} = _ActInfo, _Stime, _Etime) ->
    ok.

%% 一键领取奖励
auto_receive_reward(_Player, _Type, _SubType) ->
    ok.
