%%-----------------------------------------------------------------------------
%% @Module  :       lib_custom_act_check
%% @Author  :       Czc
%% @Email   :       389853407@qq.com
%% @Created :       2018-01-05
%% @Description:    定制活动检测模块
%%-----------------------------------------------------------------------------
-module(lib_custom_act_check).

-include("custom_act.hrl").
-include("errcode.hrl").
-include("common.hrl").
-include("server.hrl").
-include("def_fun.hrl").
-include("figure.hrl").
-include_lib("kernel/include/file.hrl").
-include("def_module.hrl").
-include("guild.hrl").
-include("def_daily.hrl").
-include("predefine.hrl").

-export([
    check_cfg/2
    , check_file_mtime/0
    , check_unique_type/1
    , check_local_unique_type/1
    , check_list/1
    , check_in_act_time/2
    , check_receive_reward/4
    , check_receive_reward_conditions/3
    , check_reward_receive_times/3
    , check_act_condtion/2
    , check_receive_reward_normal/3
    ]).

%% 检查配置是否有问题
check_cfg(Type, SubType) ->
    ActCfg = lib_custom_act_util:get_act_cfg_info(Type, SubType),
    case ActCfg of
        #custom_act_cfg{
            opday_lim = OpdayLim, merday_lim = MerdayLim,
            optype = OpType,
            opday = _OpDay, optime = OpTime,
            start_time = _Stime, end_time = _Etime,
            condition = Condition
        } ->
            if
                is_list(OpdayLim) == false -> false;
                is_list(MerdayLim) == false -> false;
                is_list(Condition) == false -> false;
                true ->
                    case lists:member(OpType, ?OPEN_TYPE_LIST) of
                        true ->
                            OpTimeL = lib_custom_act_util:format_time(OpTime),
                            case check_optime_unique(OpTimeL) of
                                true -> check_cfg(ActCfg);
                                false -> false
                            end;
                        false ->
                            false
                    end
            end;
        _ -> false
    end.

check_cfg(ActCfg) -> lib_custom_act_dispatcher:check_cfg(ActCfg).

%% 检查开启的时间段是否唯一
%% 两个时间段之间的间隔要大于1分钟
%% OpTimeL [{Stime, Etime}] Stime可为具体时间点对应的时间戳也可为时间点对应当天0点的偏移值
%% lists:sort/1排序后会按Stime从小到大排序
check_optime_unique([]) -> true;
check_optime_unique(OpTimeL) ->
    SortList = lists:sort(OpTimeL),
    do_check_optime_unique(SortList).

do_check_optime_unique([_]) -> true;
do_check_optime_unique([{AStime, AEtime}, {BStime, BEtime}|L]) ->
    case AEtime > AStime andalso BEtime > BStime andalso BStime - AEtime > 60 of
        true ->
            do_check_optime_unique([{BStime, BEtime}|L]);
        false -> false
    end.

%% 检查定制文件是否被修改过，以此判断文件是否被进行热更过
check_file_mtime() ->
    LastMtime = get(?P_CUSTOM_ACT_NORMAL_LAST_MTIME),
    NewMtime = case file:read_file_info("../ebin/data_custom_act.beam") of
        {ok, FileInfo} ->
            FileInfo#file_info.mtime;
        _ -> 0
    end,
    case LastMtime =:= NewMtime of
        true ->
            true;
        false ->
            {false, NewMtime}
    end.

%% 检查这个活动类型的活动是否只能同时开启一个
check_unique_type(_Type) -> false.

%% 跨服多开的活动在本服不能多开
check_local_unique_type(?CUSTOM_ACT_TYPE_SECKILL) -> true;
check_local_unique_type(?CUSTOM_ACT_TYPE_JUMP_ACT) -> true;
check_local_unique_type(_Type) -> false.

%% 检查活动是否在开启时间内
check_in_act_time(ActInfo, ArgsMap) ->
    case lib_custom_act_util:get_act_time_range(ActInfo, ArgsMap) of
        {Stime, Etime} ->
            #{time := NowTime} = ArgsMap,
            case NowTime >= Stime andalso NowTime < Etime of
                true -> {true, Stime, Etime};
                false -> false
            end;
        _ -> false
    end.

%% 检测是否能领取奖励
check_receive_reward(Player, Type, SubType, GradeId) ->
    NowTime = utime:unixtime(),
    case lib_custom_act_util:get_custom_act_open_info(Type, SubType) of
        #act_info{
            etime = Etime
        } = ActInfo when NowTime < Etime ->
            check_receive_reward_normal(Player, ActInfo, GradeId);
        _ ->
            {false, ?ERRCODE(err331_act_closed)}
    end.

%% 获取奖励配置，判断领取次数
check_receive_reward_normal(Player, ActInfo, GradeId) ->
    #act_info{key = {Type, SubType}} = ActInfo,
    case lib_custom_act_util:get_act_reward_cfg_info(Type, SubType, GradeId) of
        RewardCfg when is_record(RewardCfg, custom_act_reward_cfg) ->
            %% 这里不只包含次数的判断
            case check_reward_receive_times(Player, ActInfo, RewardCfg) of
                {true, NewReceiveTimes} ->
                    case check_receive_reward_special(Player, ActInfo, RewardCfg) of
                        {true, RewardList} ->
                            {true, ActInfo, NewReceiveTimes, RewardList, RewardCfg};
                        {false, Errcode} ->
                            {false, Errcode}
                    end;
                false -> {false, ?ERRCODE(err331_already_get_reward)};
                Res -> Res
            end;
        _ -> {false, ?ERRCODE(err331_no_act_reward_cfg)}
    end.

%% 先特殊处理一下
check_receive_reward_special(Player, ActInfo, RewardCfg) ->
    lib_custom_act_dispatcher:check_receive_reward_special(Player, ActInfo, RewardCfg).

%% 各个活动类型写自己的判断逻辑
check_receive_reward_conditions(Player, ActInfo, RwCfg) ->
    lib_custom_act_dispatcher:check_receive_reward_conditions(Player, ActInfo, RwCfg).

%%--------------------------------------------------
%% 检查奖励领取次数是否达到限制
%% @param  Player       #player_status{}
%% @param  ActInfo      #act_info{}
%% @param  RwInfo       #custom_act_reward_cfg{}
%% @return              {true, NewTimes}|false
%%--------------------------------------------------
check_reward_receive_times(Player, ActInfo, RwCfg) ->
    lib_custom_act_dispatcher:check_reward_receive_times(Player, ActInfo, RwCfg).

%%--------------------------------------------------
%% 检测定制活动Condition字段的配置
%% @param  List      需要检查Condition里面的Key组成的List
%% @param  Condition 定制活动Condition字段
%% @return           false|[value]
%%--------------------------------------------------
check_act_condtion(List, Condition) ->
    do_check_act_condtion(List, Condition, []).

do_check_act_condtion([], _Condition, Result) ->
    lists:reverse(Result);
do_check_act_condtion([H|List], Condition, Result) ->
    case is_atom(H) of
        true ->
            case lists:keyfind(H, 1, Condition) of
                {H, Value} ->
                    do_check_act_condtion(List, Condition, [Value|Result]);
                _ -> false
            end;
        false -> false
    end.

check_list([]) -> true;
check_list([T|L]) ->
    case do_check(T) of
        true ->
            check_list(L);
        {false, Errcode} ->
            {false, Errcode}
    end.

do_check({opday_lim, OpdayLim, Opday}) ->
    case OpdayLim =/= [] of
        true ->
            case util:is_cls() of
                false ->
                    case ulists:is_in_range(OpdayLim, Opday) of
                        false ->
                            {false, ?FAIL};
                        _ -> true
                    end;
                true -> true
            end;
        _ -> true
    end;
do_check({merday_lim, MerdayLim, MergeDay}) ->
    case MerdayLim =/= [] of
        true ->
            case MergeDay > 0 of
                true ->
            case util:is_cls() of
                false ->
                    case ulists:is_in_range(MerdayLim, MergeDay) of
                        false ->
                            {false, ?FAIL};
                        _ -> true
                    end;
                true -> true
                    end;
                _ -> {false, ?FAIL}
            end;
        _ -> true
    end;
do_check({wlv_lim, WLvLim, WorldLv}) ->
    case WLvLim =/= [] of
        true ->
            case util:is_cls() of
                false ->
                    case ulists:is_in_range(WLvLim, WorldLv) of
                        false ->
                            {false, ?FAIL};
                        _ -> true
                    end;
                true -> true
            end;
        _ -> true
    end;

do_check(_) -> {false, ?FAIL}.
