%%-----------------------------------------------------------------------------
%% @Module  :       lib_custom_act
%% @Author  :       Czc
%% @Email   :       389853407@qq.com
%% @Created :       2018-01-05
%% @Description:
%%-----------------------------------------------------------------------------
-module(lib_custom_act).

-include("custom_act.hrl").
-include("daily.hrl").
-include("common.hrl").
-include("server.hrl").
-include("errcode.hrl").
-include("def_fun.hrl").
-include("goods.hrl").
-include("figure.hrl").
-include("predefine.hrl").
-include("consume_rank_act.hrl").
-include("def_module.hrl").
-include_lib("stdlib/include/ms_transform.hrl").

-export([
    get_custom_act_list/0
    , reload_act_list/1
    , timer_check/1
    , day_trigger/1
    , pack_custom_act_list/1
    , pack_custom_act_will_open_list/1
    , get_custom_act_list_from_cfg/0
    , count_reward_status/4
    , ask_reward_status/3
    , ask_act_red_gift_status/3
    , send_reward_status/2
    , send_grade_status/2
    , receive_reward/4
    , receive_red_gift_reward/4
    , act_end/3
    , send_error_code/2
    , make_rwparam/1
    , count_receive_times/3
    , update_receive_times/5
    , broadcast_act_info/2
    , refresh_client/3
    , custom_act_send_reward/3
    , custom_act_send_reward/2
]).

-export([
    is_kf_act/2,
    sync_kf_act_info/3,
    update_receive_times_map/6
]).

%% 获取配置中有效的活动列表
get_custom_act_list() ->
    case get(?P_VAILD_ACT_TYPE_LIST) of
        undefined ->
            ActList = get_custom_act_list_from_cfg(),
            put(?P_VAILD_ACT_TYPE_LIST, ActList),
            {ok, ActList};
        ActList ->
            %% 检查文件修改时间 如果和进程字典里面存储的文件最后修改时间不一致则重新加载
            case lib_custom_act_check:check_file_mtime() of
                {false, LastMtime} ->
                    erase(?P_VAILD_ACT_TYPE_LIST),
                    put(?P_CUSTOM_ACT_NORMAL_LAST_MTIME, LastMtime),
                    {reload};
                _ ->
                    {ok, ActList}
            end
    end.

%% 重新加载定制活动
reload_act_list(State) ->
    erase(?P_VAILD_ACT_TYPE_LIST),
    OldOpenL = lib_custom_act_util:get_custom_act_open_list(),

%%    db:execute(io_lib:format(?clear_opening_custom_act, [])),
%%    ets:delete_all_objects(?ETS_CUSTOM_ACT),

    {ok, ActList} = get_custom_act_list(),

    NowTime = utime:unixtime(),
    WorldLv = util:get_world_lv(),
    ArgsMap = lib_custom_act_util:make_check_args_map(NowTime),
    F = fun(T, Acc) ->
        case T of
            {Type, SubType} ->
                case do_timer_check(Type, SubType, ArgsMap) of
                    {true, Stime, Etime} ->
                        case lists:keyfind({Type, SubType}, #act_info.key, OldOpenL) of
                            #act_info{wlv = OWLv} -> WLv = OWLv;
                            _ -> WLv = WorldLv
                        end,
                        ActInfo = #act_info{key = {Type, SubType}, wlv = WLv, stime = Stime, etime = Etime},
                        TList = act_start(?RELOAD_START, ActInfo, NowTime),
                        TList ++ Acc;
                    _ ->
                        %% 重新加载造成的活动结束当成手动结束处理
                        case lists:keyfind({Type, SubType}, #act_info.key, OldOpenL) of
                            ActInfo when is_record(ActInfo, act_info) ->
                                act_end(?CUSTOM_ACT_STATUS_MANUAL_CLOSE, ActInfo, NowTime);
                            _ ->
                                skip
                        end,
                        Acc
                end;
            _ -> Acc
        end
        end,
    lists:foldl(F, [], ActList),
    ?INFO("Reload Custom Act List", []),
    State.

%% 从配置获取定制活动列表
get_custom_act_list_from_cfg() ->
    NormalList = case data_custom_act_extra:get_switch(?CUSTOM_ACT_NORMAL) of
                     ?CUSTOM_ACT_SWITCH_OPEN ->
                         NormalCfgL = data_custom_act:get_act_list(),
                         %% 这里之后要再加一层检测,检测是否有配置除了子类型不同其他都是一样的
                         [{Type, SubType} || {Type, SubType} <- NormalCfgL, SubType < ?EXTRA_CUSTOM_ACT_SUB_ADD, lib_custom_act_check:check_cfg(Type, SubType)];
                     _ ->
                         []
                 end,
    ExtraList = case data_custom_act_extra:get_switch(?CUSTOM_ACT_EXTRA) of
                    ?CUSTOM_ACT_SWITCH_OPEN ->
                        ExtraCfgL = data_custom_act_extra:get_act_list(),
                        [{Type, SubType + ?EXTRA_CUSTOM_ACT_SUB_ADD} || {Type, SubType} <- ExtraCfgL, lib_custom_act_check:check_cfg(Type, SubType + ?EXTRA_CUSTOM_ACT_SUB_ADD)];
                    _ ->
                        []
                end,
    [{Type, SubType} || {Type, SubType} <- NormalList ++ ExtraList, lib_custom_act:is_kf_act(Type, SubType) == false].

%% 活动开启
act_start(_OpenType, ActInfo, _NowTime) ->
    #act_info{key = {Type, SubType}, wlv = WLv, stime = Stime, etime = Etime} = ActInfo,
    OpSubtypeL = lib_custom_act_util:get_open_subtype_list(Type),
    IsKfActType = is_kf_act(Type, SubType),
    case lib_custom_act_check:check_unique_type(Type) of
        true ->
            case OpSubtypeL of
                [] -> %% 同类型的活动没有开启直接开启
                    BroadCastL = [ActInfo#act_info{trigger_time = 1}],
                    case IsKfActType of
                        true -> %% 跨服的定制活动不用保存到本服数据库
                            skip;
                        _ ->
                            db:execute(io_lib:format(?insert_opening_custom_act, [Type, SubType, WLv, Stime, Etime]))
                    end,
                    ets:insert(?ETS_CUSTOM_ACT, ActInfo);
                [#act_info{key = {Type, SubType}, wlv = OWLv, stime = OStime, etime = OEtime}] when OStime =/= Stime; OEtime =/= Etime -> %% 类型相同的更新开启结束时间
                    BroadCastL = [ActInfo#act_info{wlv = OWLv}],
                    case IsKfActType of
                        true -> %% 跨服的定制活动不用保存到本服数据库
                            skip;
                        _ ->
                            db:execute(io_lib:format(?update_opening_custom_act, [Stime, Etime, Type, SubType]))
                    end,
                    ets:insert(?ETS_CUSTOM_ACT, ActInfo#act_info{wlv = OWLv});
                _ -> BroadCastL = []
            end;
        false ->
            case lists:keyfind({Type, SubType}, #act_info.key, OpSubtypeL) of
                false ->
                    BroadCastL = [ActInfo#act_info{trigger_time = 1}],
                    case IsKfActType of
                        true -> %% 跨服的定制活动不用保存到本服数据库
                            skip;
                        _ ->
                            db:execute(io_lib:format(?insert_opening_custom_act, [Type, SubType, WLv, Stime, Etime]))
                    end,
                    ets:insert(?ETS_CUSTOM_ACT, ActInfo);
                #act_info{wlv = OWLv, stime = OStime, etime = OEtime} when OStime =/= Stime; OEtime =/= Etime -> %% 类型相同的更新开启结束时间
                    BroadCastL = [ActInfo#act_info{wlv = OWLv}],
                    case IsKfActType of
                        true -> %% 跨服的定制活动不用保存到本服数据库
                            skip;
                        _ ->
                            db:execute(io_lib:format(?update_opening_custom_act, [Stime, Etime, Type, SubType]))
                    end,
                    ets:insert(?ETS_CUSTOM_ACT, ActInfo#act_info{wlv = OWLv});
                _ -> BroadCastL = []
            end
    end,
    case BroadCastL of
        [BeginActInfo] ->
            %% 通知其他功能模块定制活动的开启状态, 会在normal中广播活动开启，如果自定义活动派发接口需要处理活动开启的通知
            notify_other_module(?CUSTOM_ACT_STATUS_OPEN, IsKfActType, BeginActInfo, Stime, Etime);
        _ -> skip
    end,
    BroadCastL.

%% 活动结束

act_end(CloseType, ActInfo, NowTime) ->
    #act_info{
        key   = {Type, SubType},
        wlv   = WLv,
        stime = Stime,
        etime = Etime
    } = ActInfo,
    IsKfActType = is_kf_act(Type, SubType),
    case IsKfActType of
        false ->
            db:execute(io_lib:format(?delete_opening_custom_act, [Type, SubType]));
        _ -> skip
    end,
    ets:delete(?ETS_CUSTOM_ACT, {Type, SubType}),
    lib_log_api:log_custom_act(Type, SubType, WLv, Stime, Etime, CloseType, NowTime),
    %% 清除定制活动抽奖记录
    mod_draw_record_local:act_end(Type, SubType),
    %% 按类型处理
    notify_other_module(CloseType, IsKfActType, ActInfo, Stime, Etime),
    %% 清理活动数据
    lib_custom_act_data:act_end_clean_up_data(CloseType, ActInfo).

%% 活动结算
act_settlement(NowTime) ->
    Mspec = ets:fun2ms(fun(#act_info{etime = Etime} = T) when NowTime >= Etime -> T end),
    EndList = ets:select(?ETS_CUSTOM_ACT, Mspec),
    case EndList =/= [] of
        true ->
            ?INFO("custom_act_end:~n~p~n", [EndList]);
        _ -> skip
    end,
    F = fun(ActInfo) ->
        act_end(?CUSTOM_ACT_STATUS_CLOSE, ActInfo, NowTime)
        end,
    lists:foreach(F, EndList).

%% 每分钟检测当前是否有定制活动符合开启条件
timer_check(State) ->
    case get_custom_act_list() of
        {ok, ActList} ->
            NowTime = utime:unixtime(),
            WLv = util:get_world_lv(),
            ArgsMap = lib_custom_act_util:make_check_args_map(NowTime),
            %% 先处理已开启的活动的结算逻辑
            act_settlement(NowTime),

            F = fun(T, Acc) ->
                case T of
                    {Type, SubType} ->
                        case do_timer_check(Type, SubType, ArgsMap) of
                            {true, Stime, Etime} ->
                                ActInfo = #act_info{key = {Type, SubType}, wlv = WLv, stime = Stime, etime = Etime},
                                TList = act_start(?TIMER_START, ActInfo, NowTime),
                                TList ++ Acc;
                            _ ->
                                Acc
                        end;
                    _ -> Acc
                end
                end,
            lists:foldl(F, [], ActList),
            %% 检查同步下来的跨服定制活动是否满足开启条件
            NewState = timer_check_kf_act(State, ArgsMap),
            NewState;
        {reload} -> %% 重新加载定制活动
            reload_act_list(State)
    end.
timer_check_kf_act(State) ->
    NowTime = utime:unixtime(),
    ArgsMap = lib_custom_act_util:make_check_args_map(NowTime),
    timer_check_kf_act(State, ArgsMap).
timer_check_kf_act(State, ArgsMap) ->
    #custom_act_state{unopen_kf_act = UnOpenKfActL} = State,
    #{time := NowTime} = ArgsMap,
    WLv = util:get_world_lv(),
    F = fun(#act_info{key = {Type, SubType}} = T, {Acc, TmpBroadCastL}) ->
        %% 需要在本服检查一遍是否符合开服/合服或者其他限制条件的要求
        %% 某些活动在跨服是多开的，但是本服只能开启一种，一般配置上会避免，这里做一下预防
        CanOpen =
            case lib_custom_act_check:check_local_unique_type(Type) of
                true  ->
                    case lib_custom_act_util:get_open_subtype_list(Type) of
                        [] -> true;
                        _  -> false
                    end;
                false ->
                    true
            end,
        case CanOpen of
            true  ->
                case do_timer_check(Type, SubType, ArgsMap) of
                    {true, Stime, Etime} ->
                        ActInfo = #act_info{key = {Type, SubType}, wlv = WLv, stime = Stime, etime = Etime},
                        TList = act_start(?TIMER_START, ActInfo, NowTime),
                        {Acc, TList ++ TmpBroadCastL};
                    _ ->
                        %?ERR("Type:~p UN OPEN>>>>>>>>", [Type]),
                        {[T|Acc], TmpBroadCastL}
                end;
            false ->
                {[T|Acc], TmpBroadCastL}
        end
    end,
    {NewUnOpenKfActL, _BroadCastL} = lists:foldl(F, {[], []}, UnOpenKfActL),
    %?ERR("NewUnOpenKfActL:~p", [{NewUnOpenKfActL, UnOpenKfActL}]),
    State#custom_act_state{unopen_kf_act = NewUnOpenKfActL}.

do_timer_check(Type, SubType, ArgsMap) ->
    case lib_custom_act_util:get_act_cfg_info(Type, SubType) of
        ActInfo when is_record(ActInfo, custom_act_cfg) ->
            do_timer_check_helper(ActInfo, ArgsMap);
        _ -> false
    end.

do_timer_check_helper(ActInfo, ArgsMap) ->
    case lib_custom_act_check:check_in_act_time(ActInfo, ArgsMap) of
        {true, Stime, Etime} ->
            case do_timer_check_other(ActInfo, ArgsMap) of
                true ->
                    {true, Stime, Etime};
                _ -> false
            end;
        _ -> false
    end.

do_timer_check_other(ActInfo, ArgsMap) -> lib_custom_act_dispatcher:do_timer_check_other(ActInfo, ArgsMap).

day_trigger(?TWELVE) ->
    clear_act_data(?CUSTOM_ACT_CLEAR_ZERO),
    refresh_act_info_to_client(?CUSTOM_ACT_CLEAR_ZERO);
day_trigger(?FOUR) ->
    clear_act_data(?CUSTOM_ACT_CLEAR_FOUR),
    refresh_act_info_to_client(?CUSTOM_ACT_CLEAR_FOUR);
day_trigger(_) -> skip.


%% 零点刷新相关逻辑
refresh_act_info_to_client(ClearType) ->
    ActList = lib_custom_act_util:get_custom_act_open_list(),
    lib_player:cast_online_role_apply(
        ?APPLY_CAST_SAVE, ?MODULE, refresh_client, [ClearType,ActList]
    ),
    ok.

%% ---------------------------------------------------------------------------
%% @doc 零点刷新相关逻辑
refresh_client(Role, ClearType, ActInfoList) ->
    refresh_client_do(Role, ClearType, ActInfoList).

refresh_client_do(Role,_ClearType, []) ->
    {ok, Role};
refresh_client_do(Role,ClearType, [ActInfo | T]) ->
    NewRole = refresh_do(Role,ClearType, ActInfo),
    refresh_client_do(NewRole,ClearType,T).


refresh_do(Role, ClearType,#act_info{key = {Type, SubType}}) when Type =:= ?CUSTOM_ACT_TYPE_LIMIT_MALL ->
    #player_status{status_custom_act = StatusCustomAct}=Role,
    RewardMap  = StatusCustomAct#status_custom_act.reward_map,
    case lib_custom_act_util:get_act_cfg_info(Type, SubType) of
        #custom_act_cfg{clear_type = ClearType} ->
            RewardList0 = maps:to_list(RewardMap),
            RewardList1 = [{{T,S,G},Data}||{{T,S,G},Data}<-RewardList0,T /= Type, S /= SubType],
            NRewardMap = maps:from_list(RewardList1),
            NRole = Role#player_status{status_custom_act=StatusCustomAct#status_custom_act{reward_map=NRewardMap}};
        _ ->
            NRole = Role
    end,
    ask_reward_status(NRole, Type, SubType),
    NRole;
refresh_do(Role,_ClearType, ActInfo = #act_info{key = {?CUSTOM_ACT_TYPE_FREE_GIFT, _}}) ->
    #act_info{key = {Type, SubType}, stime = Stime, etime = Etime} = ActInfo,
    case Stime =:= Etime andalso Etime =:= 1 of
        true -> %% 是活动时间结束没有领取完奖励但需要继续显示情况
            PackList = pack_custom_act_list([ActInfo]),
            {ok, BinData} = pt_331:write(33102, [PackList]),
            lib_server_send:send_to_sid(Role#player_status.sid, BinData);
        false ->
            ok
    end,
    zero_gift:send_personal_act_info(Role, Type, SubType),
    Role;
refresh_do(Role, ClearType, #act_info{key = {Type, SubType}}) when Type =:= ?CUSTOM_ACT_TYPE_SELLSWORDS_RESUPPLY ->
    #player_status{status_custom_act = StatusCustomAct}=Role,
    RewardMap  = StatusCustomAct#status_custom_act.reward_map,
    case lib_custom_act_util:get_act_cfg_info(Type, SubType) of
        #custom_act_cfg{clear_type = ClearType} ->
            RewardList0 = maps:to_list(RewardMap),
            RewardList1 = [{{T,S,G},Data}||{{T,S,G},Data}<-RewardList0,T /= Type, S /= SubType],
            NRewardMap = maps:from_list(RewardList1),
            NRole = Role#player_status{status_custom_act=StatusCustomAct#status_custom_act{reward_map=NRewardMap}},
            {ok, BinData} = pt_331:write(33103, [Type, SubType]),
            lib_server_send:send_to_sid(Role#player_status.sid, BinData);
        _ ->
            NRole = Role
    end,
    NRole;
refresh_do(Role,_ClearType, _ActInfo) ->
    Role.

%% ================ 清理规则 ======================
%% 如果某个定制活动同时在自己的进程以及玩家进程都有数据需要清理
%% 这里只清理各个活动进程自己的数据,不处理在线玩家的定制活动数据
%% 如果要清理在线玩家身上的数据,统一在相关的活动数据加一个数据的更新时间戳字段,如果最后更新的时间戳和玩家当前操作的时间戳不在同一逻辑清理天内,则把数据清理掉
%% 判断是否在同一逻辑清理天内可调用接口lib_custom_act_util:in_same_clear_day()

%%--------------------------------------------------
%% 清理活动开启期间的数据
%% @param  ClearType CUSTOM_ACT_CLEAR_ZERO 0点 | CUSTOM_ACT_CLEAR_FOUR 4点
%% @return           description
%%--------------------------------------------------
clear_act_data(ClearType) ->
    %% 对正在开启的定制活动清理数据
    OpSubtypeL = lib_custom_act_util:get_custom_act_open_list(),
    F = fun(T) ->
        #act_info{
            key = {Type, SubType}
        } = T,
        case lib_custom_act_util:get_act_cfg_info(Type, SubType) of
            #custom_act_cfg{clear_type = ClearType} ->
                lib_custom_act_data:clear_act_data_db(Type, SubType);
            _ -> skip
        end
        end,
    lists:foreach(F, OpSubtypeL).

%% 请求活动奖励领取状态
ask_reward_status(Player, Type, SubType) ->
    lib_custom_act_dispatcher:ask_reward_status(Player, Type, SubType).

%% 请求通用活动红点礼包状态
ask_act_red_gift_status(Player, Type, SubType) ->
    lib_custom_act_dispatcher:ask_act_red_gift_status(Player, Type, SubType).

%% 特殊活动根据自己的活动类型扩展
send_reward_status(Player, ActInfo) ->
    lib_custom_act_dispatcher:send_reward_status(Player, ActInfo).

%% 发送活动某档次状态信息
%% 在合适的场合，替代33104的全量信息推送，仅推送变更的资料
send_grade_status(RoleIdOrSid, Data = [_Type, _SubType, _GradeId, _Progress, _Status, _ReceiveTimes]) ->
    {ok, BinData} = pt_331:write(33182, Data),
    if
        is_integer(RoleIdOrSid) ->
            lib_server_send:send_to_uid(RoleIdOrSid, BinData);
        is_pid(RoleIdOrSid) ->
            lib_server_send:send_to_sid(RoleIdOrSid, BinData);
        true ->
            error
    end.

%% 计算奖励可领取状态
-spec count_reward_status(Player, ActInfo, Progress, RewardCfg) -> Return when
    Player      :: #player_status{},        %% 玩家数据
    ActInfo     :: #act_info{},             %% 开启中的活动数据
    Progress    :: integer(),
    RewardCfg   :: #custom_act_reward_cfg{},%% 奖励配置
    Return      :: integer().               %% 可领取状态 0条件未满足|1可领取|2已领取|3奖励超时
count_reward_status(Player, ActInfo, Progress, RewardCfg) ->
    lib_custom_act_dispatcher:count_reward_status(Player, ActInfo, Progress, RewardCfg).

%% 领取次数
-spec count_receive_times(Player, ActInfo, RewardCfg) -> Return when
    Player      :: #player_status{},        %% 玩家数据
    ActInfo     :: #act_info{},             %% 开启中的活动数据
    RewardCfg   :: #custom_act_reward_cfg{},%% 奖励配置
    Return      :: integer().               %% 领取次数
count_receive_times(Player, ActInfo, RewardCfg) ->
    lib_custom_act_dispatcher:count_receive_times(Player, ActInfo, RewardCfg).

%% 领取奖励
receive_reward(Player, Type, SubType, GradeId) ->
    lib_custom_act_dispatcher:receive_reward(Player, Type, SubType, GradeId).

%% 领取红点礼包奖励
receive_red_gift_reward(Player, Type, SubType, GradeId) ->
    lib_custom_act_dispatcher:receive_red_gift_reward(Player, Type, SubType, GradeId).

%% 更新领奖次数
%% 注:领奖次数保存在status_custom_act的reward_map里面才使用这个接口
update_receive_times(Player, Type, SubType, GradeId, NewReceiveTimes) ->
    StatusCustomAct = Player#player_status.status_custom_act,
    RoleId = Player#player_status.id,
    NewStatusCustomAct = update_receive_times_map(RoleId, StatusCustomAct, Type, SubType, GradeId, NewReceiveTimes),
    Player#player_status{status_custom_act = NewStatusCustomAct}.
update_receive_times_map(RoleId, StatusCustomAct, Type, SubType, GradeId, NewReceiveTimes) ->
    RewardMap = StatusCustomAct#status_custom_act.reward_map,
    NowTime = utime:unixtime(),
    case maps:get({Type, SubType, GradeId}, RewardMap, []) of
        RwStatus when is_record(RwStatus, reward_status) ->
            SQL = io_lib:format(?update_custom_act_reward_receive, [NewReceiveTimes, NowTime, RoleId, Type, SubType, GradeId]),
            NewRwStatus = RwStatus#reward_status{receive_times = NewReceiveTimes, utime = NowTime};
        _ ->
            SQL = io_lib:format(?insert_custom_act_reward_receive, [RoleId, Type, SubType, GradeId, NewReceiveTimes, NowTime]),
            NewRwStatus = #reward_status{receive_times = NewReceiveTimes, utime = NowTime}
    end,
    db:execute(SQL),
    NewRewardMap = RewardMap#{{Type, SubType, GradeId} => NewRwStatus},
    StatusCustomAct#status_custom_act{reward_map = NewRewardMap}.
    
%%--------------------------------------------------
%% %% 通知其他功能模块定制活动的开启状态
%% @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, ActInfo, Stime, Etime) ->
    lib_custom_act_dispatcher:notify_other_module(ActStatus, IsKfActType, ActInfo, Stime, Etime).

%% 广播活动开启结束信息
broadcast_act_info(_, []) -> skip;
broadcast_act_info(?CUSTOM_ACT_STATUS_OPEN, ActList) ->
    PackList = pack_custom_act_list(ActList),
    {ok, BinData} = pt_331:write(33102, [PackList]),
    lib_server_send:send_to_all(BinData);
broadcast_act_info(ActStatus, TmpActList) when
    ActStatus =:= ?CUSTOM_ACT_STATUS_CLOSE
    orelse ActStatus =:= ?CUSTOM_ACT_STATUS_MANUAL_CLOSE ->
    ActList = lib_vie_rank:delay_show_acts(TmpActList),
    Info = [Key || #act_info{key = Key} <- ActList],
    {ok, BinData} = pt_331:write(33103, [Info]),
    lib_server_send:send_to_all(BinData);
broadcast_act_info(_, _ActList) -> skip.

is_kf_act(Type, _SubType) ->
    lists:member(Type, ?KF_CUSTOM_ACT_TYPE).

%% 同步跨服定制活动的信息到本服
sync_kf_act_info(ActStatusType, ActInfoL, State) when
    ActStatusType == ?CUSTOM_ACT_STATUS_CLOSE
    orelse ActStatusType == ?CUSTOM_ACT_STATUS_MANUAL_CLOSE ->
    #custom_act_state{unopen_kf_act = UnOpenKfActL} = State,
    NowTime = utime:unixtime(),
    F = fun(#act_info{key = {Type, SubType}}, Acc) ->
        case ets:lookup(?ETS_CUSTOM_ACT, {Type, SubType}) of
            [#act_info{wlv = WLv, stime = Stime, etime = Etime} = ActInfo] -> %% 从跨服中心同步过来的时候活动的世界等级默认为-1，如果这个结束的时候活动的世界等级没有变化则视为本服没有参加过这次活动
                ets:delete(?ETS_CUSTOM_ACT, {Type, SubType}),
                case WLv >= 0 of
                    true ->
                        lib_log_api:log_custom_act(Type, SubType, WLv, Stime, Etime, ActStatusType, NowTime);
                    _ -> skip
                end,
                %% 广播给玩家
                broadcast_act_info(?CUSTOM_ACT_STATUS_CLOSE, [ActInfo]),
                Acc;
            _ ->
                lists:keydelete({Type, SubType}, #act_info.key, Acc)
        end
    end,
    NewUnOpenKfActL = lists:foldl(F, UnOpenKfActL, ActInfoL),

    F1 = fun(ActInfo,Acc)->
        %% 清理活动数据
        lib_custom_act_data:act_end_clean_up_data(ActStatusType, ActInfo),
        Acc
    end,
    lists:foldl(F1, [], ActInfoL),

    State#custom_act_state{unopen_kf_act = NewUnOpenKfActL};
sync_kf_act_info(?CUSTOM_ACT_STATUS_OPEN, ActInfoL, State) ->
    #custom_act_state{unopen_kf_act = UnOpenKfActL} = State,
    timer_check_kf_act(State#custom_act_state{unopen_kf_act = ActInfoL ++ UnOpenKfActL});
sync_kf_act_info(_, _, State) -> State.

%%--------------------------------------------------
%% 打包定制活动列表
%% @param  ActList [#act_info{}]
%% @return         description
%%--------------------------------------------------
pack_custom_act_list(ActList) ->
    NowTime = utime:unixtime(),
    UnixDate = utime:unixdate(NowTime),
    F = fun(T, Acc) ->
        case T of
            #act_info{
                key   = {Type, SubType},
                wlv   = Wlv,
                stime = Stime,
                etime = Etime,
                trigger_time = TriggerTime
            } ->
                case lib_custom_act_util:get_act_cfg_info(Type, SubType) of
                    #custom_act_cfg{
                        name      = Name,
                        desc      = Desc,
                        act_type  = ActType,
                        optime    = OpTime,
                        condition = Condition
                    } ->
                        case Type of
                            %% 特定类型活动转换成真正的控制时间
                            ?CUSTOM_ACT_THEME_DUN_MUL_REWARD when OpTime =/= [] ->
                                OpTimeL  = lib_custom_act_util:format_time(OpTime, UnixDate),
                                case OpTimeL of
                                    [{StartTime, EndTime}|_] ->
                                        [{Type, SubType, ActType, Wlv, Name, Desc, util:term_to_string(Condition), StartTime, EndTime, TriggerTime} | Acc];
                                    _ ->
                                        [{Type, SubType, ActType, Wlv, Name, Desc, util:term_to_string(Condition), Stime, Etime, TriggerTime} | Acc]
                                end;
                            _ ->
                                [{Type, SubType, ActType, Wlv, Name, Desc, util:term_to_string(Condition), Stime, Etime, TriggerTime} | Acc]
                        end;
                    _ -> Acc
                end;
            _ -> Acc
        end
        end,
    lists:foldl(F, [], ActList).

%%--------------------------------------------------
%% 打包预开启定制活动列表
%% @param  ActList [{#custom_act_cfg{}, StTime}]
%% @return         description
%%--------------------------------------------------
pack_custom_act_will_open_list(ActList) ->
    F = fun({T, Stime}, Acc) ->
        case T of
            #custom_act_cfg{
                type = Type,
                subtype = SubType,
                act_type = ActType,
                name = Name,
                desc = Desc,
                condition = Condition
            } ->
                [{Type, SubType, ActType, Name, Desc, util:term_to_string(Condition), Stime} | Acc];
            _ -> Acc
        end
        end,
    lists:foldl(F, [], ActList).

%% 发送错误码
send_error_code(RoleId, ErrorCode) when is_integer(RoleId) ->
    {ok, BinData} = pt_331:write(33100, [ErrorCode]),
    lib_server_send:send_to_uid(RoleId, BinData);
send_error_code(Sid, ErrorCode) when is_pid(Sid) ->
    {ok, BinData} = pt_331:write(33100, [ErrorCode]),
    lib_server_send:send_to_sid(Sid, BinData).

make_rwparam(#player_status{figure = #figure{lv = Lv, sex = Sex, career = Career}}) ->
    Wlv = util:get_world_lv(),
    #reward_param{player_lv = Lv, sex = Sex, wlv = Wlv, career = Career}.

%% ---------------------------------------------------------------------------
%% @doc 定制活动发送奖励。
-spec custom_act_send_reward(Player, RewardList, RewardCfg) ->
    {false, Reason} | NewPlayer when
    Player      :: #player_status{},
    RewardList  :: list(),
    RewardCfg   :: #custom_act_reward_cfg{},
    Reason      :: integer(),
    NewPlayer   :: #player_status{}.
%% ---------------------------------------------------------------------------
custom_act_send_reward(Player, RewardList, RewardCfg) ->
    case lib_goods_api:can_give_goods(Player, RewardList) of
        true ->
            NewRewardCfg = RewardCfg#custom_act_reward_cfg{reward = RewardList},
            custom_act_send_reward(Player, NewRewardCfg);
        false ->
            {false, ?ERRCODE(err150_no_cell)}
    end.


%% ---------------------------------------------------------------------------
%% @doc 定制活动发送奖励。
-spec custom_act_send_reward(Player, RewardCfg) -> NewPlayer when
    Player      :: #player_status{},
    RewardCfg   :: #custom_act_reward_cfg{},
    NewPlayer   :: #player_status{}.
%% ---------------------------------------------------------------------------
custom_act_send_reward(Player = #player_status{id = _Id}, RewardCfg) ->
    #custom_act_reward_cfg{
        type = Type, subtype = SubType, grade = _Grade, reward = RewardList
    } = RewardCfg,
    Produce = #produce{
        type = custom_act, subtype = Type, reward = RewardList
        ,remark = ulists:concat(["type:", Type, " subtype:", SubType, " grade:", _Grade])
    },
    NewPlayer = lib_goods_api:send_reward(Player, Produce),
    % %% 写日志
    % RewardStr = util:term_to_string(RewardList),
    % lib_log_api:log_role_custom_act(Id, Type, SubType, Grade, RewardStr),
    NewPlayer.

