%%-----------------------------------------------------------------------------
%% @Module  :       lib_custom_act_util
%% @Author  :       Czc
%% @Email   :       389853407@qq.com
%% @Created :       2018-01-06
%% @Description:    定制活动工具类
%%-----------------------------------------------------------------------------
-module(lib_custom_act_util).

-include("custom_act.hrl").
-include("errcode.hrl").
-include("common.hrl").
-include("server.hrl").
-include("figure.hrl").
-include("def_module.hrl").
-include_lib("stdlib/include/ms_transform.hrl").

-export([
        %% 配置读取
        get_act_cfg_info/2                  %% 获取活动配置 #custom_act_cfg{}
        , get_act_reward_cfg_info/3         %% 获取奖励配置 #custom_act_reward_cfg{} | []
        , get_act_reward_cfg_list/2         %% 获取活动奖励列表 [#custom_act_reward_cfg{}]
        , get_act_reward_grade_list/2       %% 获取活动所有档次奖励id [grade]
        , get_subtype_list/1                %% 获取主类型下的子类型列表 [sub_type]
        , get_custom_act_kv/3               %% 获取活动通用配置

        %% 获取活动开放列表/单个信息 #act_info{} | [#act_info{}].
        , get_custom_act_open_info/2
        , get_custom_act_open_list/0
        , get_open_subtype_list/1
        , get_open_subtype_list/2
        , get_custom_act_will_open_list/0
        , get_act_time_range_by_type/2
        , get_act_time_range/2
        , format_time/1
        , format_time/2
        , make_check_args_map/0
        , make_check_args_map/1
        , in_same_clear_day/4
        , count_act_reward/3
        , count_act_reward/2
        , keyfind_act_condition/2
        , keyfind_act_condition/3
        , keyfind_reward_condition/5
        , get_act_name/2
        , get_act_open_lv/1
        , get_act_open_lv/2         %% 获取活动开启等级
    ]).

%%--------------------------------------------------
%% 获取活动配置信息
%% @param  Type    活动主类型
%% @param  SubType 活动子类型
%% @return         #custom_act_cfg{}|[]
%%--------------------------------------------------
get_act_cfg_info(Type, SubType) ->
    case SubType < ?EXTRA_CUSTOM_ACT_SUB_ADD of
        true ->
            case data_custom_act_extra:get_switch(?CUSTOM_ACT_NORMAL) of
                ?CUSTOM_ACT_SWITCH_OPEN ->
                    data_custom_act:get_act_info(Type, SubType);
                _ ->
                    []
            end;
        _ ->
            case data_custom_act_extra:get_switch(?CUSTOM_ACT_EXTRA) of
                ?CUSTOM_ACT_SWITCH_OPEN ->
                    data_custom_act_extra:get_act_info(Type, SubType - ?EXTRA_CUSTOM_ACT_SUB_ADD);
                _ ->
                    []
            end
    end.

%%--------------------------------------------------
%% 获取活动奖励
%% @param  Type    活动主类型
%% @param  SubType 活动子类型
%% @param  Grade   奖励档次
%% @return         #custom_act_reward_cfg{}|[]
%%--------------------------------------------------
get_act_reward_cfg_info(Type, SubType, Grade) ->
    case SubType < ?EXTRA_CUSTOM_ACT_SUB_ADD of
        true ->
            case data_custom_act_extra:get_switch(?CUSTOM_ACT_NORMAL) of
                ?CUSTOM_ACT_SWITCH_OPEN ->
                    data_custom_act:get_reward_info(Type, SubType, Grade);
                _ ->
                    []
            end;
        _ ->
            case data_custom_act_extra:get_switch(?CUSTOM_ACT_EXTRA) of
                ?CUSTOM_ACT_SWITCH_OPEN ->
                    data_custom_act_extra:get_reward_info(Type, SubType - ?EXTRA_CUSTOM_ACT_SUB_ADD, Grade);
                _ ->
                    []
            end
    end.

%% ---------------------------------------------------------------------------
%% @doc 获取活动奖励列表
-spec get_act_reward_cfg_list(Type, SubType) -> Return when
    Type        :: integer(),
    SubType     :: integer(),
    Return      :: [#custom_act_reward_cfg{}].
%% ---------------------------------------------------------------------------
get_act_reward_cfg_list(Type, SubType) ->
    case SubType < ?EXTRA_CUSTOM_ACT_SUB_ADD of
        true ->
            case data_custom_act_extra:get_switch(?CUSTOM_ACT_NORMAL) of
                ?CUSTOM_ACT_SWITCH_OPEN ->
                    GradeList = data_custom_act:get_reward_grade_list(Type, SubType),
                    [
                        data_custom_act:get_reward_info(Type, SubType, Grade) ||
                        Grade <- GradeList
                    ];
                _ ->
                    []
            end;
        _ ->
            case data_custom_act_extra:get_switch(?CUSTOM_ACT_EXTRA) of
                ?CUSTOM_ACT_SWITCH_OPEN ->
                    GradeList = data_custom_act_extra:get_reward_grade_list(Type, SubType - ?EXTRA_CUSTOM_ACT_SUB_ADD),
                    [
                        data_custom_act_extra:get_reward_info(Type, SubType, Grade) ||
                        Grade <- GradeList
                    ];
                _ ->
                    []
            end
    end.

%%--------------------------------------------------
%% 获取活动所有档次奖励id
%% @param  Type    活动主类型
%% @param  SubType 活动子类型
%% @return         [grade]
%%--------------------------------------------------
get_act_reward_grade_list(Type, SubType) ->
    case SubType < ?EXTRA_CUSTOM_ACT_SUB_ADD of
        true ->
            case data_custom_act_extra:get_switch(?CUSTOM_ACT_NORMAL) of
                ?CUSTOM_ACT_SWITCH_OPEN ->
                    data_custom_act:get_reward_grade_list(Type, SubType);
                _ ->
                    []
            end;
        _ ->
            case data_custom_act_extra:get_switch(?CUSTOM_ACT_EXTRA) of
                ?CUSTOM_ACT_SWITCH_OPEN ->
                    data_custom_act_extra:get_reward_grade_list(Type, SubType - ?EXTRA_CUSTOM_ACT_SUB_ADD);
                _ ->
                    []
            end
    end.

%%--------------------------------------------------
%% 获取主类型下的子类型列表
%% @return [sub_type]
%%--------------------------------------------------
get_subtype_list(Type) ->
    List1 = case data_custom_act_extra:get_switch(?CUSTOM_ACT_NORMAL) of
        ?CUSTOM_ACT_SWITCH_OPEN ->
            data_custom_act:get_act_subtype(Type);
        _ ->
            []
    end,
    List2 = case data_custom_act_extra:get_switch(?CUSTOM_ACT_EXTRA) of
        ?CUSTOM_ACT_SWITCH_OPEN ->
            [TmpId + ?EXTRA_CUSTOM_ACT_SUB_ADD || TmpId <- data_custom_act_extra:get_act_subtype(Type)];
        _ ->
            []
    end,
    List1 ++ List2.

%%--------------------------------------------------
%% 获取活动通用配置
%% @return Any
%%--------------------------------------------------
get_custom_act_kv(Type, Key, Default) ->
    case data_custom_act:get_custom_act_kv(Type, Key) of
        [Value] -> Value;
        _ -> Default
    end.

%%--------------------------------------------------
%% 获取开启中的活动列表
%% @return [#act_info{}]
%%--------------------------------------------------
get_custom_act_open_list() ->
    NowTime = utime:unixtime(),
    Mspec = ets:fun2ms(
        fun(#act_info{etime = Etime} = T) when NowTime < Etime -> T end
    ),
    ets:select(?ETS_CUSTOM_ACT, Mspec).

%%--------------------------------------------------
%% 获取活动开启信息
%% @return #act_info{}|false
%%--------------------------------------------------
get_custom_act_open_info(Type, SubType) ->
    case ets:lookup(?ETS_CUSTOM_ACT, {Type, SubType}) of
        [ActInfo|_] when is_record(ActInfo, act_info) ->
            ActInfo;
        _ -> false
    end.

%%--------------------------------------------------
%% 获取当前主类型开启的活动列表
%% @param  Type 活动主类型
%% @return      [#act_info{}]
%%--------------------------------------------------
get_open_subtype_list(Type) ->
    NowTime = utime:unixtime(),
    get_open_subtype_list(Type, NowTime).

get_open_subtype_list(Type, NowTime) ->
    Mspec = ets:fun2ms(fun(#act_info{key = {_Type, _Subtype}, etime = Etime} = T) when Type =:= _Type, NowTime < Etime ->
        T
    end),
    List = ets:select(?ETS_CUSTOM_ACT, Mspec),
    F = fun(#act_info{key = {_, ASubtype}}, #act_info{key = {_, BSubtype}}) ->
        ASubtype =< BSubtype
    end,
    lists:sort(F, List).

%%--------------------------------------------------
%% 获取预开启的活动列表
%% @return      [{#custom_act_cfg{}, StTime}]
%%--------------------------------------------------
get_custom_act_will_open_list() ->
    NeedCheck = [],
    ArgsMap = lib_custom_act_util:make_check_args_map(),
    FilterCheck = [Type || Type <- NeedCheck, get_open_subtype_list(Type) == []],
    get_custom_act_will_open_list(FilterCheck, ArgsMap, []).

get_custom_act_will_open_list([], _ArgsMap, WillOpenList) -> WillOpenList;
get_custom_act_will_open_list([Type | T], ArgsMap, WillOpenList) ->
    SubList = get_subtype_list(Type),
    Fun = fun(SubType, TmpList) ->
        case get_custom_act_will_open_time(Type, SubType, ArgsMap) of
            {ActInfo, StTime} ->
                [{ActInfo, StTime} | TmpList];
            _ -> TmpList
        end
    end,
    NewWillOpenList = lists:foldl(Fun, WillOpenList, SubList),
    get_custom_act_will_open_list(T, ArgsMap, NewWillOpenList).

%%可根据各自定制活动处理，不处理则走通用
get_custom_act_will_open_time(Type, SubType, ArgsMap) ->
    #{time := Now, unixdate := ZeroSt } = ArgsMap,
    case get_act_time_range_by_type(Type, SubType) of
        {StTime, _} when StTime > Now->
            case utime:unixdate(StTime) of
                ZeroSt ->
                    ActInfo = get_act_cfg_info(Type, SubType),
                    {ActInfo, StTime};
                _ ->
                    false
            end;
        _ -> false
    end.

%%--------------------------------------------------
%% 获取活动开启的时间范围
%% @param  Type    活动主类型
%% @param  SubType 活动子类型
%% @return         description
%%--------------------------------------------------
get_act_time_range_by_type(Type, SubType) ->
    case get_act_cfg_info(Type, SubType) of
        ActInfo when is_record(ActInfo, custom_act_cfg) ->
            ArgsMap = make_check_args_map(),
            get_act_time_range(ActInfo, ArgsMap);
        _ ->
            false
    end.

%%--------------------------------------------------
%% 获取活动开启的时间范围
%% @param  ActInfo #custom_act_cfg{}
%% @param  ArgsMap #{}
%% @return         {Stime, Etime}
%%--------------------------------------------------
get_act_time_range(ActInfo, ArgsMap) ->
    #custom_act_cfg{
        opday_lim = OpdayLim,
        merday_lim = MerdayLim
    } = ActInfo,
    #{opday := Opday, merday := MergeDay} = ArgsMap,
    CheckList = [{opday_lim, OpdayLim, Opday}, {merday_lim, MerdayLim, MergeDay}],
    case lib_custom_act_check:check_list(CheckList) of
        true ->
            do_get_act_time_range(ActInfo, ArgsMap);
        _ -> false
    end.

%%20200721 追加{cycle_days,3} {cycle_location,1} 设定
do_get_act_time_range(#custom_act_cfg{optype = ?OPEN_TYPE_SPECIFY_TIME} = ActInfo, ArgsMap) ->
    #custom_act_cfg{
        opday_lim = OpdayLim, merday_lim = MerdayLim,
        start_time = Stime, end_time = Etime,condition=Conditions
    } = ActInfo,
    IsCls = util:is_cls(),
    #{opday := Opday, merday := MergeDay} = ArgsMap,
    case lists:keyfind(cycle_days,1,Conditions) of
        {_,CDay}->
            skip;
        _->
            CDay = false
    end,
    case lists:keyfind(cycle_location,1,Conditions) of
        {_,Loc} when is_integer(CDay) andalso not IsCls ->
            Opday = util:get_open_day(),
            Rem = Opday rem CDay,
            IsCys = Loc =:= Rem,
            IsCycle = true;
        _->
            IsCys = true,IsCycle=false
    end,
    case OpdayLim =/= [] andalso not IsCls of
        true ->
            {MinOpdayLim, MaxOpdayLim} = ulists:is_in_range(OpdayLim, Opday),
            OpTime = util:get_open_time(),
            OpUnixDate = utime:unixdate(OpTime),
            OpdayTimeLim = case IsCys andalso IsCycle of
                true->
                    [{OpUnixDate + (MinOpdayLim - 1) * 86400, OpUnixDate + Opday*86400-1}];
                _->
                    [{OpUnixDate + (MinOpdayLim - 1) * 86400, OpUnixDate + MaxOpdayLim * 86400 - 1}]
            end;
        false ->
            OpdayTimeLim = []
    end,
    case MerdayLim =/= [] andalso not IsCls of
        true ->
            {MinMerdayLim, MaxMerdayLim} = ulists:is_in_range(MerdayLim, MergeDay),
            MergeTime = util:get_merge_time(),
            MergeUnixDate = utime:unixdate(MergeTime),
            MerdayTimeLim = [{MergeUnixDate + (MinMerdayLim - 1) * 86400, MergeUnixDate + MaxMerdayLim * 86400 - 1}];
        false ->
            MerdayTimeLim = []
    end,
    TimeLimL = OpdayTimeLim ++ MerdayTimeLim ++ [{Stime, Etime}],
    StL = [St || {St, _} <- TimeLimL, St > 0],
    EtL = [Et || {_, Et} <- TimeLimL, Et > 0],
    case StL =/= [] andalso EtL =/= [] of
        true when IsCys ->
            {lists:max(StL), lists:min(EtL)};
        _ -> false
    end;
do_get_act_time_range(#custom_act_cfg{optype = ?OPEN_TYPE_WEEK} = ActInfo, ArgsMap) ->
    #custom_act_cfg{
        opday = OpDay,
        optime = OpTime
    } = ActInfo,
    #{time := NowTime, unixdate := UnixDate, week := Week} = ArgsMap,
    case OpDay =:= [] orelse lists:member(Week, OpDay) of
        true ->
            case OpTime =/= [] of
                true ->
                    OpTimeL = lib_custom_act_util:format_time(OpTime, UnixDate),
                    case ulists:is_in_range(OpTimeL, NowTime) of
                        {Stime, Etime} when NowTime < Etime ->
                            {Stime, Etime};
                        _ ->
                           false
                    end;
                false ->
                    {UnixDate, UnixDate + ?ACT_DURATION_ONE_DAY}
            end;
        false -> false
    end;
do_get_act_time_range(#custom_act_cfg{optype = ?OPEN_TYPE_MONTH} = ActInfo, ArgsMap) ->
    #custom_act_cfg{
        opday = OpDay,
        optime = OpTime
    } = ActInfo,
    #{time := NowTime, unixdate := UnixDate, date := Date} = ArgsMap,
    {{_Y, _M, D}, _} = Date,
    case OpDay =:= [] orelse lists:member(D, OpDay) of
        true ->
            case OpTime =/= [] of
                true ->
                    OpTimeL = lib_custom_act_util:format_time(OpTime, UnixDate),
                    case ulists:is_in_range(OpTimeL, NowTime) of
                        {Stime, Etime} when NowTime < Etime ->
                            {Stime, Etime};
                        _ ->
                           false
                    end;
                false ->
                    {UnixDate, UnixDate + ?ACT_DURATION_ONE_DAY}
            end;
        false -> false
    end;
do_get_act_time_range(#custom_act_cfg{optype = ?OPEN_TYPE_SPECIFY_DATE} = ActInfo, ArgsMap) ->
    #custom_act_cfg{
        opday = OpDay,
        optime = OpTime
    } = ActInfo,
    #{time := NowTime, unixdate := UnixDate, date := Date} = ArgsMap,
    {YMD, _} = Date,
    case OpDay =:= [] orelse lists:member(YMD, OpDay) of
        true ->
            case OpTime =/= [] of
                true ->
                    OpTimeL = lib_custom_act_util:format_time(OpTime, UnixDate),
                    case ulists:is_in_range(OpTimeL, NowTime) of
                        {Stime, Etime} when NowTime < Etime ->
                            {Stime, Etime};
                        _ ->
                           false
                    end;
                false ->
                    {UnixDate, UnixDate + 86400}
            end;
        false -> false
    end;
do_get_act_time_range(#custom_act_cfg{optype = ?OPEN_TYPE_CONTINUOUS_WEEK} = ActInfo, ArgsMap) ->
    #custom_act_cfg{
        opday_lim = OpdayLim,
        merday_lim = MerdayLim,
        opday = OpDay
    } = ActInfo,
    IsCls = util:is_cls(),
    #{time := NowTime, unixdate := UnixDate, week := Week, opday := Opday, merday := MergeDay} = ArgsMap,
    case OpdayLim =/= [] andalso not IsCls of
        true ->
            {MinOpdayLim, MaxOpdayLim} = ulists:is_in_range(OpdayLim, Opday),
            OpTime = util:get_open_time(),
            OpUnixDate = utime:unixdate(OpTime),
            OpdayTimeLim = [{OpUnixDate + (MinOpdayLim - 1) * 86400, OpUnixDate + MaxOpdayLim * 86400 - 1}];
        false -> OpdayTimeLim = []
    end,
    case MerdayLim =/= [] andalso not IsCls of
        true ->
            {MinMerdayLim, MaxMerdayLim} = ulists:is_in_range(MerdayLim, MergeDay),
            MergeTime = util:get_merge_time(),
            MergeUnixDate = utime:unixdate(MergeTime),
            MerdayTimeLim = [{MergeUnixDate + (MinMerdayLim - 1) * 86400, MergeUnixDate + MaxMerdayLim * 86400 - 1}];
        false -> MerdayTimeLim = []
    end,
    case lists:member(Week, OpDay) of
        true ->
            case utime:is_continuous_week(OpDay) of
                true ->
                    CurWeek = utime:day_of_week(NowTime),
                    {StartSpace, EndSpace} = count_week_space(OpDay, CurWeek, false, 0, 0),
                    {Stime, Etime} = {UnixDate - StartSpace * ?ONE_DAY_SECONDS, UnixDate + EndSpace * ?ONE_DAY_SECONDS + ?ACT_DURATION_ONE_DAY},
                    TimeLimL = OpdayTimeLim ++ MerdayTimeLim ++ [{Stime, Etime}],
                    StL = [St || {St, _} <- TimeLimL, St > 0],
                    EtL = [Et || {_, Et} <- TimeLimL, Et > 0],
                    case StL =/= [] andalso EtL =/= [] of
                        true ->
                            {lists:max(StL), lists:min(EtL)};
                        false -> false
                    end;
                _ -> false
            end;
        false -> false
    end;
do_get_act_time_range(#custom_act_cfg{optype = ?OPEN_TYPE_REPEAT_OPEN} = ActInfo, ArgsMap) ->
    #custom_act_cfg{
        condition = Condition
    } = ActInfo,
    IsCls = util:is_cls(),
    IsMerge = util:is_merge_game(),
    #{time := _NowTime, opday := Opday, merday := MergeDay} = ArgsMap,
    if
        IsCls -> false;
        true ->
            if
                IsMerge -> %% 合服后用合服天数判断
                    OpDay = MergeDay,
                    OpTime = util:get_merge_time();
                true ->
                    OpDay = Opday,
                    OpTime = util:get_open_time()
            end,
            case {check_cycle_daily_open(Condition, OpDay, begin_time), check_cycle_daily_open(Condition, OpDay, end_time)} of
                {StartTime, EndTime} when is_integer(StartTime), is_integer(EndTime) ->
                    {OpTime + StartTime, OpTime + EndTime};
                _ -> false
            end
    end.

%% 计算OPEN_TYPE_CONTINUOUS_WEEK模式定制活动的开始周/结束周到当前周的间隔
count_week_space([], _CurWeek, _IsConfirmStart, StartSpace, EndSpace) -> {StartSpace, EndSpace};
count_week_space([Week|WeekL], CurWeek, IsConfirmStart, StartSpace, EndSpace) ->
    case Week == CurWeek of
        true ->
            count_week_space(WeekL, CurWeek, true, StartSpace, 0);
        false ->
            case IsConfirmStart of
                true ->
                    count_week_space(WeekL, CurWeek, IsConfirmStart, StartSpace, EndSpace + 1);
                _ ->
                    count_week_space(WeekL, CurWeek, IsConfirmStart, StartSpace + 1, EndSpace)
            end
    end.

%% 构建参数Map
make_check_args_map() ->
    NowTime = utime:unixtime(),
    make_check_args_map(NowTime).

make_check_args_map(NowTime) ->
    UnixDate = utime:unixdate(NowTime),
    Opday = util:get_open_day(NowTime),
    MergeDay = util:get_merge_day(NowTime),
    Week = utime:day_of_week(NowTime),
    Date = utime:unixtime_to_localtime(NowTime),
    #{time => NowTime, unixdate => UnixDate, opday => Opday, merday => MergeDay,  week => Week, date => Date}.

%% 格式化开启的时间段
%% return 时间点对应当天0点的偏移值组成的列表
format_time(TimeL) ->
    [{SH * 3600 + SM * 60 + SS, EH * 3600 + EM * 60 + ES}||{{SH, SM, SS}, {EH, EM, ES}} <- TimeL].
%% 格式化开启的时间段
%% return 当天时间点对应的时间戳组成的列表
format_time(TimeL, _DateTime) ->
    {NowDate, {_NowH, _NowM, _}} = calendar:local_time(),
    [{utime:unixtime({NowDate, {SH, SM, SS}}), utime:unixtime({NowDate, {EH, EM, ES}})}||{{SH, SM, SS}, {EH, EM, ES}} <- TimeL].

%% ---------------------------------------------------------------------------
%% @doc 检查是否根据开服天数或者合服天数，每天循环开启
-spec check_cycle_daily_open(Condition, DayNth, Type) -> Return when
    Condition   :: [tuple()],
    DayNth      :: integer(),
    Type        :: begin_time | end_time,
    Return      :: false | Time,
    Time        :: integer().
%% ---------------------------------------------------------------------------
%% {cycle_startday, StartDay}:循环开始时间
%% {cycle_days, DivisorDays, RemNum}:DivisorDays循环内的总天数 RemNum循环内的第几天
%% {cycle_days, DivisorDays, RemList}:DivisorDays循环内的总天数 RemList循环内的【连续天数】列表
check_cycle_daily_open(Condition, DayNth, Type) ->
    case lists:keyfind(cycle_startday, 1, Condition) of
        {cycle_startday, StartDay} when DayNth >= StartDay ->
            case lists:keyfind(cycle_days, 1, Condition) of
                {cycle_days, DivisorDays, RemNum} when is_integer(DivisorDays), is_integer(RemNum) ->
                    case DayNth rem DivisorDays of
                        RemNum ->
                            case Type of
                                begin_time -> (DayNth - 1) * 86400;
                                end_time -> DayNth * 86400
                            end;
                        _ ->
                            false
                    end;
                {cycle_days, DivisorDays, RemList} when is_integer(DivisorDays), is_list(RemList) ->
                    RemNum = DayNth rem DivisorDays,
                    case lists:reverse(lists:sort(RemList)) of
                        [MaxRem|_] -> skip;
                        _ -> MaxRem = 0
                    end,
                    case {lists:member(RemNum, RemList), Type} of
                        {true, begin_time} -> (DayNth - 1) * 86400;
                        {true, end_time} -> (DayNth + max(MaxRem - RemNum, 0)) * 86400;
                        _ ->
                            false
                    end;
                _ ->
                    false
            end;
        _ ->
            false
    end.

%%--------------------------------------------------
%% 判断是否在同一逻辑清理天内
%% 比如活动凌晨4点清理,当天4点到明天4点都属于同一天
%% @param  Type    活动主类型
%% @param  SubType 活动子类型
%% @param  Time1   时间戳
%% @param  Time2   时间戳
%% @return         description
%%--------------------------------------------------
in_same_clear_day(Type, SubType, Time1, Time2) ->
    case get_act_cfg_info(Type, SubType) of
        #custom_act_cfg{clear_type = ClearType} ->
            case ClearType of
                ?CUSTOM_ACT_CLEAR_ZERO ->
                    utime:is_same_day(Time1, Time2);
                ?CUSTOM_ACT_CLEAR_FOUR ->
                    utime:is_logic_same_day(Time1, Time2);
                _ ->
                    true
            end;
        _ -> true
    end.

%% 计算定制活动的奖励
count_act_reward(Player, ActInfo, RewardCfg) ->
    case RewardCfg of
        #custom_act_reward_cfg{} ->
            RewardList = do_count_act_reward(Player, ActInfo, RewardCfg),
            lib_custom_act_dispatcher:count_act_reward_other(ActInfo, RewardList);
        _ -> []
    end.

%% 用参数计算的奖励
count_act_reward(RewardParam, RewardCfg) ->
    case RewardCfg of
        #custom_act_reward_cfg{type = Type, subtype = SubType} ->
            RewardList = do_count_act_reward(RewardParam, RewardCfg),
            case get_custom_act_open_info(Type, SubType) of
                ActInfo when is_record(ActInfo, act_info) ->
                    lib_custom_act_dispatcher:count_act_reward_other(ActInfo, RewardList);
                _ ->
                    RewardList
            end;
        _ -> []
    end.

%% 计算定制活动的奖励
do_count_act_reward(_Player, _ActInfo, #custom_act_reward_cfg{format = ?REWARD_FORMAT_TYPE_COMMON} = RewardCfg) ->
    RewardCfg#custom_act_reward_cfg.reward;
do_count_act_reward(Player, _ActInfo, #custom_act_reward_cfg{format = ?REWARD_FORMAT_TYPE_LV} = RewardCfg) ->
    #player_status{figure = Figure} = Player,
    #figure{lv = RoleLv} = Figure,
    #custom_act_reward_cfg{format = FormatType, reward = CandidateList} = RewardCfg,
    SortL = lists:keysort(1, CandidateList),
    filter_reward(FormatType, SortL, RoleLv, []);
do_count_act_reward(_Player, _ActInfo, #custom_act_reward_cfg{format = ?REWARD_FORMAT_TYPE_RAND} = RewardCfg) ->
    #custom_act_reward_cfg{format = FormatType, reward = CandidateList} = RewardCfg,
    filter_reward(FormatType, CandidateList, [], []);
do_count_act_reward(_Player, #act_info{wlv = WLv}, #custom_act_reward_cfg{format = ?REWARD_FORMAT_TYPE_WLV} = RewardCfg) ->
    #custom_act_reward_cfg{format = FormatType, reward = CandidateList} = RewardCfg,
    SortL = lists:keysort(1, CandidateList),
    filter_reward(FormatType, SortL, WLv, []);
do_count_act_reward(#player_status{figure = Figure}, _ActInfo, #custom_act_reward_cfg{format = ?REWARD_FORMAT_TYPE_CAREER} = RewardCfg) ->
    #custom_act_reward_cfg{reward = CandidateList} = RewardCfg,
    case lists:keyfind(Figure#figure.career, 1, CandidateList) of
        {_Career, RewardList} -> RewardList;
        _ -> []
    end;
do_count_act_reward(Player, _ActInfo, #custom_act_reward_cfg{format = ?REWARD_FORMAT_TYPE_SPECIFY_LV} = RewardCfg) ->
    #player_status{figure = Figure} = Player,
    #figure{lv = RoleLv} = Figure,
    #custom_act_reward_cfg{format = FormatType, reward = CandidateList} = RewardCfg,
    filter_reward(FormatType, CandidateList, RoleLv, []);
do_count_act_reward(Player, _ActInfo, #custom_act_reward_cfg{format = ?REWARD_FORMAT_TYPE_SPECIFY_LVACAREER} = RewardCfg) ->
    #player_status{figure = Figure} = Player,
    #figure{lv = RoleLv, career = Career} = Figure,
    #custom_act_reward_cfg{format = FormatType, reward = CandidateList} = RewardCfg,
    filter_reward(FormatType, CandidateList, {RoleLv, Career}, []);
do_count_act_reward(Player, #act_info{wlv = WLv}, #custom_act_reward_cfg{format = ?REWARD_FORMAT_TYPE_SPECIFY_WLVACAREER} = RewardCfg) ->
    #player_status{figure = Figure} = Player,
    #figure{career = Career} = Figure,
    #custom_act_reward_cfg{format = FormatType, reward = CandidateList} = RewardCfg,
    filter_reward(FormatType, CandidateList, {WLv, Career}, []);
do_count_act_reward(_Player, _ActInfo, _) ->
    [].

%% 用参数计算的奖励
do_count_act_reward(_, #custom_act_reward_cfg{format = ?REWARD_FORMAT_TYPE_COMMON} = RewardCfg) ->
    RewardCfg#custom_act_reward_cfg.reward;
do_count_act_reward(#reward_param{player_lv = RoleLv}, #custom_act_reward_cfg{format = ?REWARD_FORMAT_TYPE_LV} = RewardCfg) ->
    #custom_act_reward_cfg{format = FormatType, reward = CandidateList} = RewardCfg,
    SortL = lists:keysort(1, CandidateList),
    filter_reward(FormatType, SortL, RoleLv, []);
do_count_act_reward(_, #custom_act_reward_cfg{format = ?REWARD_FORMAT_TYPE_RAND} = RewardCfg) ->
    #custom_act_reward_cfg{format = FormatType, reward = CandidateList} = RewardCfg,
    filter_reward(FormatType, CandidateList, [], []);
do_count_act_reward(#reward_param{wlv = WLv}, #custom_act_reward_cfg{format = ?REWARD_FORMAT_TYPE_WLV} = RewardCfg) ->
    #custom_act_reward_cfg{format = FormatType, reward = CandidateList} = RewardCfg,
    SortL = lists:keysort(1, CandidateList),
    filter_reward(FormatType, SortL, WLv, []);
do_count_act_reward(#reward_param{career = Career}, #custom_act_reward_cfg{format = ?REWARD_FORMAT_TYPE_CAREER} = RewardCfg) ->
    #custom_act_reward_cfg{reward = CandidateList} = RewardCfg,
    case lists:keyfind(Career, 1, CandidateList) of
        {Career, RewardList} -> RewardList;
        _ -> []
    end;
do_count_act_reward(#reward_param{player_lv = RoleLv}, #custom_act_reward_cfg{format = ?REWARD_FORMAT_TYPE_SPECIFY_LV} = RewardCfg) ->
    #custom_act_reward_cfg{format = FormatType, reward = CandidateList} = RewardCfg,
    filter_reward(FormatType, CandidateList, RoleLv, []);
do_count_act_reward(#reward_param{player_lv = RoleLv, career = Career}, #custom_act_reward_cfg{format = ?REWARD_FORMAT_TYPE_SPECIFY_LVACAREER} = RewardCfg) ->
    #custom_act_reward_cfg{format = FormatType, reward = CandidateList} = RewardCfg,
    filter_reward(FormatType, CandidateList, {RoleLv, Career}, []);
do_count_act_reward(#reward_param{wlv = WLv, career = Career}, #custom_act_reward_cfg{format = ?REWARD_FORMAT_TYPE_SPECIFY_WLVACAREER} = RewardCfg) ->
    #custom_act_reward_cfg{format = FormatType, reward = CandidateList} = RewardCfg,
    filter_reward(FormatType, CandidateList, {WLv, Career}, []);
do_count_act_reward(_, _) -> [].

filter_reward(_, [], _, CurReward) -> CurReward;
filter_reward(?REWARD_FORMAT_TYPE_LV = Type, [{LimLv, T}|L], RoleLv, CurReward) ->
    case RoleLv >= LimLv of
        true ->
            filter_reward(Type, L, RoleLv, T);
        false -> CurReward
    end;
filter_reward(?REWARD_FORMAT_TYPE_RAND = _Type, List, _, _) ->
    case urand:rand_with_weight(List) of
        RewardList when is_list(RewardList) -> RewardList;
        _ -> []
    end;
filter_reward(?REWARD_FORMAT_TYPE_WLV = Type, [{LimLv, T}|L], WLv, CurReward) ->
    case WLv >= LimLv of
        true ->
            filter_reward(Type, L, WLv, T);
        false -> CurReward
    end;
filter_reward(?REWARD_FORMAT_TYPE_SPECIFY_LV = Type, [{[MinLv, MaxLv], T}|L], RoleLv, CurReward) ->
    case RoleLv >= MinLv andalso RoleLv =< MaxLv of
        true -> T;
        false -> filter_reward(Type, L, RoleLv, CurReward)
    end;
filter_reward(?REWARD_FORMAT_TYPE_SPECIFY_LVACAREER = Type, [{[MinLv, MaxLv], T}|L], {RoleLv, Career}, CurReward) ->
    case RoleLv >= MinLv andalso RoleLv =< MaxLv of
        true ->
            case lists:keyfind(Career, 1, T) of
                {Career, RewardList} -> RewardList;
                _ -> []
            end;
        false -> filter_reward(Type, L, {RoleLv, Career}, CurReward)
    end;
filter_reward(?REWARD_FORMAT_TYPE_SPECIFY_WLVACAREER = Type, [{[MinLv, MaxLv], T}|L], {WLv, Career}, CurReward) ->
    case WLv >= MinLv andalso WLv =< MaxLv of
        true ->
            case lists:keyfind(Career, 1, T) of
                {Career, RewardList} -> RewardList;
                _ -> []
            end;
        false -> filter_reward(Type, L, {WLv, Career}, CurReward)
    end;
filter_reward(_Type, _, _, CurReward) -> CurReward.

%%--------------------------------------------------
%% 查找活动条件
%% @return false | {max_lv, MaxLv}...
%%--------------------------------------------------
keyfind_reward_condition(Type, SubType, GradeId, Key, Default) ->
    Config = get_act_reward_cfg_info(Type, SubType, GradeId),
    case is_record(Config, custom_act_reward_cfg) of
        true ->
            case lists:keyfind(Key, 1, Config#custom_act_reward_cfg.condition) of
                {_, Value} ->
                    Value;
                _ ->
                    Default
            end;
        false ->
            Default
    end.

keyfind_act_condition(Type, SubType, Key) ->
    Config = get_act_cfg_info(Type, SubType),
    case is_record(Config, custom_act_cfg) of
        true -> keyfind_act_condition(Config, Key);
        false -> false
    end.

keyfind_act_condition(Act, Key) when is_record(Act, custom_act_cfg) ->
    keyfind_act_condition(Act#custom_act_cfg.condition, Key);
keyfind_act_condition(Condition, Key) ->
    lists:keyfind(Key, 1, Condition).

get_act_name(Type, SubType) ->
    case get_act_cfg_info(Type, SubType) of
        #custom_act_cfg{name = Name} ->
            util:make_sure_binary(Name);
        _ ->
            <<>>
    end.

%%--------------------------------------------------
%% 获取活动开启等级
%%--------------------------------------------------
get_act_open_lv(Type) ->
    SubTypeL = lib_custom_act_api:get_open_subtype_ids(Type),
    case SubTypeL of
        [SubType | _T] -> get_act_open_lv(Type, SubType);
        _ -> 9999
    end.

get_act_open_lv(Type, SubType) ->
    case lib_custom_act_util:get_act_cfg_info(Type, SubType) of
        #custom_act_cfg{condition = Condition} when is_list(Condition) ->
            case lists:keyfind(role_lv, 1, Condition) of
                {_, Lv} when is_integer(Lv) -> Lv;
                _ ->
                    case lib_module:get_open_lv(?MOD_AC_CUSTOM, Type) of
                        Lv when Lv > 1000 -> 0;
                        Lv -> Lv
                    end
            end;
        _ -> 0
    end.
