%% ---------------------------------------------------------------------------
%% @doc 定制活动-全民动员。
%% @author zmh
%% @since  20200811
%% ---------------------------------------------------------------------------
-module(custom_act_mobilize).


-export([
    send_mobilize_task_info/1       %% 发送全民动员活动信息
    ,send_mobilize_task_info/2      %% 发送全民动员活动信息
    ,receive_mobilize_task_award/4  %% 领取全民动员任务完成奖励
    ,update_mobilize_task/3         %% 更新全民动员进度
    ,update_mobilize_task/4         %% 更新全民动员进度
    ,update_mobilize_task/5         %% 更新全民动员进度
    ,handle_event/2                 %% 处理通用事件
    ,update_mobilize_gem_task/3     %% 装备宝石等级提升事件
    ,login/1
    ,finish_dungeon/3
    ,finish_dungeon/4
    ,get_task_fake/2
    ,receive_mobilize_day_award/4   %% 领取天数进度奖励
    ,task_type_from_start_to_end/6  %% 计算统计的开始和结束时间
    ,get_update_times/2
    ,get_start_end_day/2
    ,notify_other_module/5

    ,get_lv_key/1
    ,get_vip_key/1
    ,is_lv_finish/1
]).


-include("custom_act.hrl").
-include("custom_act_mobilize.hrl").
-include("common.hrl").
-include("server.hrl").
-include("dungeon.hrl").
-include("errcode.hrl").
-include("def_goods.hrl").
-include("def_fun.hrl").
-include("def_module.hrl").
-include("goods.hrl").
-include("figure.hrl").
-include("predefine.hrl").
-include("def_event.hrl").
-include("rec_event.hrl").
-include("recharge_act.hrl").
-include("rec_recharge.hrl").
-include("contract.hrl").
-include("equipment.hrl").

%% 登录更新全民动员战力
login(RoleId) ->
    Sql = io_lib:format(?SQL_SELECT_MOBILIZE_POWER, [RoleId]),
    case db:get_row(Sql) of
        [Power] -> Power;
        _ -> 0
    end.

%% 发送全民动员活动信息(更新推送)
send_mobilize_task_info(Role) ->
    case lib_custom_act_api:get_open_custom_act_infos(?CUSTOM_ACT_TYPE_MOBILIZE) of
        [_|_] = ActInfos ->
            [send_mobilize_task_info(Role, ActInfo) || ActInfo <- ActInfos];
        _ ->
            ok
    end,
    ok.
send_mobilize_task_info(Role, ActInfo = #act_info{key = {?CUSTOM_ACT_TYPE_MOBILIZE, _}}) ->
    send_mobilize_task_info_do(Role, ActInfo);

%% 发送全民动员活动信息(协议请求)
send_mobilize_task_info(Role, SubType) ->
    ActInfo = lib_custom_act_util:get_custom_act_open_info(?CUSTOM_ACT_TYPE_MOBILIZE, SubType),
    send_mobilize_task_info_do(Role, ActInfo),
    ok.

send_mobilize_task_info_do(Role, ActInfo = #act_info{}) ->
    #act_info{key = {_Type, SubType}} = ActInfo,
    Now = utime:unixtime(),
    DayInfoList = case ActInfo of
        #act_info{etime = ETime} when ETime > Now ->
            mobilize_task_info(Role, ActInfo, Now);
        _ ->
            []
    end,
    {ok, Bin} = pt_332:write(33225, [SubType, DayInfoList]),
    lib_server_send:send_to_sid(Role#player_status.sid, Bin),
    ok;
send_mobilize_task_info_do(_Role, _ActInfo) ->
    ok.

%% 全民动员任务数据
mobilize_task_data(Role, Type, SubType) ->
    RoleId = Role#player_status.id,
    #mobilize_act_data{
        act_data = ActData
    } = mobilize_data:custom_act_data(RoleId, Type, SubType),
    case ActData of
        #mobilize_role{} ->
            ActData;
        _ ->
            #mobilize_role{}
    end.

%% @doc 全民动员活动信息 @end
mobilize_task_info(Role, ActInfo = #act_info{key = {?CUSTOM_ACT_TYPE_MOBILIZE, _}}, Now) ->
    #act_info{key = {Type, SubType}, stime = StartTime} = ActInfo,
    FakeMap = mod_mobilize_mgr:get_fake_map(),
    NowDay = utime:day_span(StartTime, Now),
    DayList = data_custom_mobilize:get_day_list(SubType),
    Filter = fun({StartDay, EndDay}, TList) ->
                case StartDay =< NowDay andalso NowDay =< EndDay of
                    true -> [{StartDay, EndDay}|TList];
                    _ -> TList
                end end,
    DayList1 = lists:foldl(Filter, [], DayList),
    TaskActData = mobilize_task_data(Role, Type, SubType),
    DayInfoList = day_info_list(DayList1, TaskActData, ActInfo, NowDay, Role, FakeMap, []),
    DayInfoList.

%% 全民动员每天信息
day_info_list([], _TaskActData, _ActInfo, _NowDay, _Role, _FakeMap, DayInfoList) ->
    DayInfoList;
day_info_list([{SDay, EDay} = DayInterval | T], TaskActData, ActInfo, NowDay, Role, FakeMap, DayInfoList) ->
    #act_info{key = {_Type, SubType}} = ActInfo,
    TypeIdList = data_custom_mobilize:get_task_type_id_list(SubType, SDay, EDay),
    #mobilize_role{day_list = DayDataList, task_stat = TaskStatMap} = TaskActData,
    TaskList = maps:get(DayInterval, TaskStatMap, []),
    TaskDayData = case lists:keyfind(DayInterval, #mobilize_day.day_interval, DayDataList) of
        TDayData = #mobilize_day{} -> TDayData;
        _ -> #mobilize_day{day_interval = DayInterval}
    end,
    #mobilize_day{total = Total, state = State} = TaskDayData,
    DayTaskList = day_task_list(
        TypeIdList, TaskList, TaskStatMap, ActInfo, NowDay, Role, FakeMap, []
    ),
    DayInfo = {SDay, EDay, Total, State, DayTaskList},
    DayInfoList2 = [DayInfo | DayInfoList],
    day_info_list(T, TaskActData, ActInfo, NowDay, Role, FakeMap, DayInfoList2);
day_info_list([_|T], TaskActData, ActInfo, NowDay, Role, FakeMap, DayInfoList) ->
    day_info_list(T, TaskActData, ActInfo, NowDay, Role, FakeMap, DayInfoList).

%% 每天的任务展示内容
day_task_list([], _TaskList, _TaskStatMap, _ActInfo, _NowDay, _Role, _FakeMap, DayTaskList) ->
    DayTaskList;
day_task_list([TaskTypeId | T], TaskList, TaskStatMap, ActInfo, NowDay, Role, FakeMap, DayTaskList) ->
    TaskIdList = data_custom_mobilize:get_task_id_list(TaskTypeId),
    % #act_info{key = {_, SubType}} = ActInfo,
    OpenDay = util:get_open_day(),
    case lists:keyfind(TaskTypeId, #mobilize_task.task_type, TaskList) of
        #mobilize_task{} = TaskData -> ok;
        _ -> TaskData = #mobilize_task{}
    end,
    F = fun(TaskId, TList) ->
        case data_custom_mobilize:get_mobilize_task(TaskTypeId, TaskId) of
            #custom_mobilize_task{day = StartDay, end_day = EndDay}
                when StartDay =< OpenDay andalso OpenDay =< EndDay ->
                [TaskId|TList];
            _ ->
                TList
        end end,
    TaskIdList1 = lists:foldl(F, [], TaskIdList),
    DayTaskList2 = type_task_list(
        TaskIdList1, TaskTypeId, TaskData, TaskStatMap, ActInfo, NowDay, Role, FakeMap, DayTaskList
    ),
%%        _ ->
%%            F = fun(TaskId, TList) ->
%%                case data_custom_mobilize:get_mobilize_task(TaskTypeId, TaskId) of
%%                    #custom_mobilize_task{day = StartDay, end_day = EndDay}
%%                        when StartDay =< OpenDay andalso OpenDay =< EndDay ->
%%                        FakeId = get_task_fake(SubType, TaskTypeId),
%%                        Key    = {TaskTypeId, FakeId, StartDay},
%%                        #fake_cord{process = ServerPro} = maps:get(Key, FakeMap, #fake_cord{}),
%%                        [{TaskTypeId, TaskId, ServerPro, 0, 0, 0}|TList];
%%                    _ ->
%%                        TList
%%                end end,
%%            DayTaskList1 = lists:foldl(F, [], TaskIdList),
%%            DayTaskList2 = DayTaskList1++DayTaskList
%%    end,
    day_task_list(T, TaskList, TaskStatMap, ActInfo, NowDay, Role, FakeMap, DayTaskList2).

%% 每种类型的任务只显示一个任务
type_task_list(
    [], _TaskTypeId, _TaskData, _TaskStatMap, _ActInfo, _NowDay, _Role, _FakeMap, TypeTaskList
) ->
    TypeTaskList;
type_task_list(
    [TaskId | T], TaskTypeId, TaskData, TaskStatMap, ActInfo, NowDay, Role, FakeMap, TypeTaskList
) ->
    case data_custom_mobilize:get_mobilize_task(TaskTypeId, TaskId) of
        TaskCfg = #custom_mobilize_task{} ->
            {
                Status, ServerPro, PersonPro,GainPro
            } = task_award_status(ActInfo, TaskData, TaskStatMap, TaskCfg, Role, FakeMap),
            TaskInfo = {TaskTypeId, TaskId, ServerPro, PersonPro, GainPro, Status},
            %% 每种类型的任务只显示一个任务
            NTypeTaskList = case Status of
                ?ACT_REWARD_CAN_GET -> %% 可以领取，展示这个任务
                    [TaskInfo | TypeTaskList];
                ?ACT_REWARD_CAN_NOT_GET -> %% 还没完成，展示这个任务
                    [TaskInfo | TypeTaskList];
                _ -> %% 任务奖励已经领取
                    case T of
                        [] -> %% 这个类型的任务，最后一个也完成了
                            [TaskInfo | TypeTaskList];
                        _ -> %% 还有下一个任务
                            [TaskInfo | TypeTaskList]
                    end
            end,
            type_task_list(T, TaskTypeId, TaskData, TaskStatMap, ActInfo,NowDay, Role, FakeMap, NTypeTaskList);
        _ ->
            type_task_list(T, TaskTypeId, TaskData, TaskStatMap, ActInfo, NowDay, Role, FakeMap, TypeTaskList)
    end.

%% 计算统计开始和结束时间
%% 1> 首充、投资、0元礼包、尊享卡、直购礼包、vip1/vip3、万物宝典需要从活动开始时间开始统计
%% 2> 除1> 之外的按配置的开始天数开始统计
%% CalcStartKeys = [
%%                recharge, investment, freegift, supremecard, directbuy,
%%                passport, vip1, vip3
%%            ],
task_type_from_start_to_end(_SubType, _TaskTypeId, StartDay, EndDay, ActSTime, ActETime) ->
    case StartDay > 0 andalso EndDay > 0 of
        true ->
            STime = utime:that_day_after(ActSTime, max(0, StartDay-1)),
            ETime = utime:that_day_after(ActSTime, max(0, EndDay)),
            {STime, ETime};
        _ ->
            {ActSTime, ActETime}
    end.

get_start_end_day(SubType, TaskTypeId) ->
    case data_custom_mobilize:get_day_interval(SubType, TaskTypeId) of
        [{_, _} = First|_] = List ->
            {StartDay, _} = First,
            {_, EndDay} = lists:last(List),
            {StartDay, EndDay};
        _ ->
            {0, 0}
    end.

%% @doc
%% 领取任务完成奖励
%%      领取任务奖励的同时，更新天数大奖进度
%% @end
receive_mobilize_task_award(Role, SubType, TaskTypeId, TaskId) ->
    Now = utime:unixtime(),
    {
        IsOpen, NowDay, ActInfo
    } = case lib_custom_act_util:get_custom_act_open_info(?CUSTOM_ACT_TYPE_MOBILIZE, SubType) of
        ActInfo0 = #act_info{stime = StartTime, etime = ETime} when ETime > Now ->
            {true, utime:day_span(StartTime, Now), ActInfo0};
        _ ->
            {false, 0, #act_info{}}
    end,
    TaskCfg = data_custom_mobilize:get_mobilize_task(TaskTypeId, TaskId),
    {
        AwardList, StartDay, EndDay
    } = case TaskCfg of
        #custom_mobilize_task{reward = Award, day = TStartDay, end_day = TEndDay} ->
            {Award, TStartDay, TEndDay};
        _ ->
            {[], 0, 0}
    end,
    TypeList   = data_custom_mobilize:get_task_type_id_list(SubType, StartDay, EndDay),
    TaskIdList = data_custom_mobilize:get_task_id_list(TaskTypeId),
    IsDayAward = lists:member(TaskTypeId, TypeList)
                    andalso lists:member(TaskId, TaskIdList),
    #player_status{id = RoleId, figure=#figure{name = RName}} = Role,
    if
        IsOpen =:= false ->
            {false, ?ERRCODE(err331_act_closed)};
        AwardList =:= [] ->
            {false, ?ERRCODE(err331_no_act_reward_cfg)};
        not IsDayAward ->
            {false, ?ERRCODE(missing_config)};
        not (NowDay >= StartDay andalso NowDay =< EndDay) ->
            {false, ?ERRCODE(err333_can_not_get)};
        true ->
            MobilizeData = #mobilize_role{
                day_list = DayDataList, task_stat = TaskStatMap
            } = mobilize_task_data(Role, ?CUSTOM_ACT_TYPE_MOBILIZE, SubType),
            %% 全服进度数据
            FakeMap = mod_mobilize_mgr:get_fake_map(),
            DayInterval = {StartDay, EndDay},
            {
                TaskDayData, RestDayDataList
            } = case lists:keytake(DayInterval, #mobilize_day.day_interval, DayDataList) of
                {value, TDayData = #mobilize_day{}, RestList} ->
                    {TDayData, RestList};
                _ ->
                    {#mobilize_day{day_interval = DayInterval}, DayDataList}
            end,
            TaskList = maps:get(DayInterval, TaskStatMap, []),
            TaskData = case lists:keytake(TaskTypeId, #mobilize_task.task_type, TaskList) of
                {value, TTaskData = #mobilize_task{}, _RestList} ->
                    TTaskData;
                _ ->
                    #mobilize_task{task_type = TaskTypeId, day_interval = DayInterval}
            end,
            %% 领取状态
            {
                Status, _ServerPro, _PersonPro, _GainPro
            } = task_award_status(ActInfo, TaskData, TaskStatMap, TaskCfg, Role, FakeMap),
            if
                Status =:= ?ACT_REWARD_HAS_GET ->
                    {false, ?ERRCODE(err331_already_get_reward)};
                Status =:= ?ACT_REWARD_CAN_NOT_GET ->
                    {false, ?ERRCODE(err333_can_not_get)};
                true ->
                    %% 任务数据
                    #mobilize_task{task_pro = TaskPro, task_award_log = AwardLog} = TaskData,
                    AwardLog2 = [TaskId | AwardLog],
                    NewTaskData = TaskData#mobilize_task{task_award_log = AwardLog2},
                    NewTaskList = lists:keystore(TaskTypeId, #mobilize_task.task_type, TaskList, NewTaskData),
                    NewTaskStatMap = maps:put(DayInterval, NewTaskList, TaskStatMap),
                    %% 天数大奖数据
                    #mobilize_day{total = CurTotal, state = CurState} = TaskDayData,
                    NewTotal = CurTotal + 1,
                    case data_custom_mobilize:get_act_day_reward(SubType, StartDay, EndDay) of
                        #base_custom_mobilize_day{need_num = NeedNum} -> ok;
                        _ -> NeedNum = ?MOBILIZE_DAY_REWARD_DEFAULT_NEED
                    end,
                    TotalState = check_total_state(NewTotal, NeedNum, TypeList, CurState),
                    TaskDayData2 = TaskDayData#mobilize_day{
                        total = NewTotal, state = TotalState
                    },
                    DayDataList2  = [TaskDayData2 | RestDayDataList],
                    MobilizeData2 = MobilizeData#mobilize_role{
                        task_stat = NewTaskStatMap,
                        day_list  = DayDataList2
                    },
                    ActData = #mobilize_act_data{
                        type = ?CUSTOM_ACT_TYPE_MOBILIZE, subtype = SubType, act_data = MobilizeData2
                    },
                    %% 保存数据
                    mobilize_data:save_custom_data(RoleId, ActData),
                    TaskInfo = {StartDay, EndDay, TaskTypeId, TaskPro, AwardLog2},
                    mobilize_data:db_save_mobilize_task(RoleId, SubType, TaskInfo),

                    DaysInfo = {StartDay, EndDay, NewTotal, TotalState},
                    mobilize_data:db_save_mobilize_days_reward(RoleId, SubType, DaysInfo),

                    %% 发奖励
                    Produce = #produce{
                        type = mobilize_task_award, subtype = SubType, reward = AwardList
                        ,remark = io_lib:format("~w,~w", [TaskTypeId, TaskId])
                    },
                    lib_goods_api:send_reward_with_mail(Role, Produce),
                    lib_log_api:log_mobilize_award(RoleId,RName,SubType,1,StartDay,EndDay,TaskTypeId,TaskId,AwardList),
                    {ok, Role}
            end
    end.

%% @doc 领取天数大奖 @end
receive_mobilize_day_award(Role, SubType, StartDay, EndDay) ->
    #player_status{id = RoleId, figure=#figure{name = RName}} = Role,
    MobilizeData = #mobilize_role{
        day_list = DayDataList
    } = mobilize_task_data(Role, ?CUSTOM_ACT_TYPE_MOBILIZE, SubType),
    DayInterval = {StartDay, EndDay},
    {
        TaskDayData, RestDayDataList
    } = case lists:keytake(DayInterval, #mobilize_day.day_interval, DayDataList) of
        {value, TDayData = #mobilize_day{}, RestList} ->
            {TDayData, RestList};
        _ ->
            {#mobilize_day{day_interval = DayInterval}, DayDataList}
    end,
    AwardList = case data_custom_mobilize:get_act_day_reward(SubType, StartDay, EndDay) of
                    #base_custom_mobilize_day{reward = TReward} -> TReward;
                    _ -> []
                end,
    #mobilize_day{state = CurState, total = Total} = TaskDayData,
    if
        CurState  =:= 0 ->
            {false, ?ERRCODE(err331_act_can_not_get)};
        CurState  =:= 2 ->
            {false, ?ERRCODE(err331_already_get_reward)};
        AwardList =:= [] ->
            {false, ?ERRCODE(err331_no_act_reward_cfg)};
        true ->
            NewState = 2,
            TaskDayData2 = TaskDayData#mobilize_day{state = NewState},
            DayDataList2 = [TaskDayData2 | RestDayDataList],
            MobilizeData2 = MobilizeData#mobilize_role{day_list = DayDataList2},
            ActData = #mobilize_act_data{
                type = ?CUSTOM_ACT_TYPE_MOBILIZE, subtype = SubType, act_data = MobilizeData2
            },
            %% 保存数据
            mobilize_data:save_custom_data(RoleId, ActData),
            DaysInfo = {StartDay, EndDay, Total, NewState},
            mobilize_data:db_save_mobilize_days_reward(RoleId, SubType, DaysInfo),

            %% 发奖励
            Produce = #produce{
                type = mobilize_task_award, subtype = SubType, reward = AwardList
                ,remark = io_lib:format("~w,~w", [SubType, DayInterval])
            },
            lib_goods_api:send_reward_with_mail(Role, Produce),

            %% 传闻
            case AwardList of
                [{_, RewardId, _}|_] -> ok;
                _ -> RewardId = 0
            end,
            lib_chat:send_TV({all}, ?MOD_AC_CUSTOM, ?CUSTOM_ACT_TYPE_MOBILIZE, [RName, RewardId]),

            lib_log_api:log_mobilize_award(RoleId,RName,SubType,2,StartDay,EndDay,0,0,AwardList),
            {ok,Role}
    end.

%% 任务奖励状态
task_award_status(ActInfo, TaskData, TaskStatMap, TaskCfg, Role, FakeMap) ->
    #custom_mobilize_task{
        task_type = TaskTypeId
        ,task_id  = TaskId
        ,server_pro = ServerNeed
        ,person_pro = PersonNeed
        ,gain_con   = GainNeed
        ,day        = StartDay
        ,end_day    = EndDay
    } = TaskCfg,
    #mobilize_task{task_award_log = TaskAwardLog, task_pro = TaskPro} = TaskData,
    IsMember = lists:member(TaskId, TaskAwardLog),
    #act_info{key={_, SubType}, stime = ActSTime, etime = ActETime} = ActInfo,
    #player_status{id = RoleId, figure = Figure, mobilize_combat_power = MobilizePower} = Role,
    %% 1> 全服进度
    FakeId = get_task_fake(SubType, TaskTypeId),
    Key    = {TaskTypeId, FakeId, StartDay},
    #fake_cord{process = ServerPro} = maps:get(Key, FakeMap, #fake_cord{}),
    %% 2> 个人进度
    {_STime, ETime} = task_type_from_start_to_end(SubType, TaskTypeId, StartDay, EndDay, ActSTime, ActETime),
    TaskType = data_custom_mobilize:get_task_type(TaskTypeId),
    IsLvTask = lists:member(TaskType, [lv70, lv90, lv100, lv110, lv120, lv130, lv135]),
    PersonPro = if
                    TaskType == firstrecharge ->
                        ?IF(lib_recharge_data:get_my_recharge_between(RoleId, ActSTime, ETime) > 0, 1, 0);
                    IsLvTask ->
                        Figure#figure.lv;
                    TaskType == power ->
                        MobilizePower;
                    true ->
                        TaskPro
    end,
    %% 3> 硬性条件检查
    TaskStateList = maps:get({StartDay, EndDay}, TaskStatMap, []),
    GainPro = check_gain_pro(Role, ActInfo, {StartDay, EndDay}, GainNeed, TaskTypeId, TaskStateList),

    IsSerFinish = ServerPro >= ServerNeed,

    if
        IsMember ->
            {?ACT_REWARD_HAS_GET, ServerPro, PersonPro, GainPro};
        PersonPro >= PersonNeed andalso IsSerFinish andalso GainPro == 1 ->
            {?ACT_REWARD_CAN_GET, ServerPro, PersonPro, GainPro};
        true ->
            {?ACT_REWARD_CAN_NOT_GET, ServerPro, PersonPro, GainPro}
    end.


%% @doc 更新全民动员进度 @end
%% param: TaskType :: atom() 任务类型
update_mobilize_task(RoleId, TaskType, Add) ->
    update_mobilize_task(RoleId, TaskType, Add, false).

%% 更新全民动员进度 IsDayLimit  :: boolean(). %% 是否每日只统计一次
update_mobilize_task(RoleId, TaskType, Add, IsDayLimit) when is_integer(RoleId) ->
    Args = [TaskType, Add, IsDayLimit],
    lib_player:apply_cast(RoleId, ?APPLY_CAST_STATUS, ?MODULE, update_mobilize_task, Args);
update_mobilize_task(Role, TaskType, Add, IsDayLimit) ->
    case lib_custom_act_api:get_open_custom_act_infos(?CUSTOM_ACT_TYPE_MOBILIZE) of
        [_|_] = Acts ->
            [
                update_mobilize_task(Role, ActInfo, TaskType, Add, IsDayLimit, ?MOBILIZE_CALC_SUM)
                || ActInfo = #act_info{} <- Acts
            ];
        _ ->
            ok
    end,
    ok.

%% 更新全民动员进度
%% IsDayLimit  :: boolean(). %% 是否每日只统计一次
%% CalcType    :: integer(). %% 统计类型 1-替换更新 2-累加
update_mobilize_task(Role, TaskType, Value, IsDayLimit, CalcType) ->
    case lib_custom_act_api:get_open_custom_act_infos(?CUSTOM_ACT_TYPE_MOBILIZE) of
        [_|_] = Acts ->
            [
                update_mobilize_task(Role, ActInfo, TaskType, Value, IsDayLimit, CalcType)
                || ActInfo = #act_info{} <- Acts
            ];
        _ ->
            ok
    end,
    ok.

update_mobilize_task(Role, ActInfo, TaskType, Value, IsDayLimit, CalcType) ->
    #act_info{key = {_Type, SubType}} = ActInfo,
    TypeIdList = data_custom_mobilize:get_task_type_id_list_by_subtype(SubType),
    TaskTypeId = data_custom_mobilize:get_task_type_id(TaskType),
    case lists:member(TaskTypeId, TypeIdList) of
        false -> %% 此活动没有此类型的任务
            ok;
        true ->
            OpenDay = util:get_open_day(),
            DayList = data_custom_mobilize:get_day_interval(SubType, TaskTypeId),
            % ?INFO_TTY("DayList is ~w~n",[DayList]),
            %% 有些任务需要统计之前的进度，所以天数未达到也需要开始统计
            TaskCalcType = data_custom_mobilize:get_calc_type(TaskTypeId),
            F = fun({StartDay, EndDay}) ->
                case TaskCalcType == 1 of
                    true ->
                        case OpenDay =< EndDay of
                            true ->
                                update_mobilize_task_do(
                                    Role, {StartDay, EndDay}, ActInfo, TaskTypeId, Value, IsDayLimit, CalcType
                                );
                            _ ->
                                ignore
                        end;
                    _ ->
                        case StartDay =< OpenDay andalso OpenDay =< EndDay of
                            true ->
                                update_mobilize_task_do(
                                    Role, {StartDay, EndDay}, ActInfo, TaskTypeId, Value, IsDayLimit, CalcType
                                );
                            _ ->
                                ignore
                        end
                end end,
            lists:map(F, DayList)
    end.

update_mobilize_task_do(Role, {StartDay, EndDay} = DayInterval, ActInfo, TaskTypeId, Value, IsDayLimit, CalcType) ->
    #act_info{key = {Type, SubType}, stime = STime, etime = ETime} = ActInfo,
    MobilizeData = #mobilize_role{
        task_stat = TaskStatMap
    } = mobilize_task_data(Role, Type, SubType),
    Now = utime:unixtime(),
    %{StartDay, EndDay} = get_start_end_day(SubType, TaskTypeId),
    TaskStatList = maps:get({StartDay, EndDay}, TaskStatMap, []),
    KeyPos = #mobilize_task.task_type,
    {TaskStatList2, IsUpdate} = case lists:keytake(TaskTypeId, KeyPos, TaskStatList) of
        {
            value, Task = #mobilize_task{task_pro = Num, time = Time}, RestList
        } when IsDayLimit ->
            %% 等级任务如果触发过，就不需要再触发了
            IsLvTask = lists:member(TaskTypeId, [10,11,12,13,14,15,16]),
            case IsLvTask == true andalso Time > 0 of
                true ->
                    {TaskStatList, false};
                _ ->
                    case utime:is_same_day(Time, Now) of
                        true ->
                            {TaskStatList, false};
                        _ ->
                            {NewPro, TUpdate} = case CalcType of
                                                    ?MOBILIZE_CALC_UPDATE when Value > Num -> {Value, true};
                                                    ?MOBILIZE_CALC_UPDATE -> {Num, false};
                                                    _ -> {Num + Value, true}
                                                end,
                            {[Task#mobilize_task{task_pro = NewPro, time = Now} | RestList], TUpdate}
                    end
            end;
        {value, Task = #mobilize_task{task_pro = Num}, RestList} ->
            {NewPro, TUpdate} = case CalcType of
                                    ?MOBILIZE_CALC_UPDATE when Value > Num -> {Value, true};
                                    ?MOBILIZE_CALC_UPDATE -> {Num, false};
                                    _ -> {Num + Value, true}
                                end,
            {[Task#mobilize_task{task_pro = NewPro, time = Now} | RestList], TUpdate};
        _ ->
            Task = #mobilize_task{
                task_type = TaskTypeId, task_pro = Value, day_interval = {StartDay, EndDay}, time = Now
            },
            {[Task | TaskStatList], true}
    end,
    case IsUpdate of
        true ->
            NewTaskStateMap = maps:put({StartDay, EndDay}, TaskStatList2, TaskStatMap),
            MobilizeData2 = MobilizeData#mobilize_role{task_stat = NewTaskStateMap},
            TaskData = lists:keyfind(TaskTypeId, KeyPos, TaskStatList2),
            #mobilize_task{task_pro = TaskPro, task_award_log = AwardLog} = TaskData,
            ActData = #mobilize_act_data{
                type = Type, subtype = SubType, act_data = MobilizeData2
            },
            #player_status{id = RoleId} = Role,
            % lib_custom_act_data:save_custom_data(RoleId, ActData),
            mobilize_data:save_custom_data(RoleId, ActData),
            TaskInfo = {StartDay, EndDay, TaskTypeId, TaskPro, AwardLog},
            mobilize_data:db_save_mobilize_task(RoleId, SubType, TaskInfo),
            %% 宝石更新需要差值
            TaskType = data_custom_mobilize:get_task_type(TaskTypeId),
            % UpdateTimes = get_update_times(RoleId, TaskTypeId),
            CheckSpec = lists:member(TaskType, ?MOBILIZE_SPEC_TASK_TYPE_LIST),
            OldValue = case lists:keyfind(TaskTypeId, KeyPos, TaskStatList) of
                           #mobilize_task{task_pro = TValue} when CheckSpec == true ->
                               TValue;
                           _ -> 0
                       end,
            case CheckSpec of
                true ->
                    Value > OldValue andalso
                        mod_mobilize_mgr:cast({sync_server_precess, SubType, DayInterval, STime, ETime, TaskTypeId, Value, OldValue});
                _ ->
                    mod_mobilize_mgr:cast({sync_server_precess, SubType, DayInterval, STime, ETime, TaskTypeId, Value, OldValue})
            end,
            send_mobilize_task_info(Role, ActInfo);
        _ ->
            ok
    end,
    ok.

get_update_times(RoleId, TaskTypeId) ->
    case data_custom_mobilize:get_task_type(TaskTypeId) of
        combat ->
            Times = lib_counter:get_count(RoleId, ?MOD_AC_CUSTOM, ?CUSTOM_ACT_TYPE_MOBILIZE, 1),
            case Times =< 0 of
                true -> update_times(RoleId, TaskTypeId);
                _ -> ignore
            end,
            Times;
        warsoul ->
            Times = lib_counter:get_count(RoleId, ?MOD_AC_CUSTOM, ?CUSTOM_ACT_TYPE_MOBILIZE, 2),
            case Times =< 0 of
                true -> update_times(RoleId, TaskTypeId);
                _ -> ignore
            end,
            Times;
        _ ->
            0
    end.

update_times(RoleId, TaskTypeId) ->
    case data_custom_mobilize:get_task_type(TaskTypeId) of
        combat ->
            lib_counter:increment(RoleId, ?MOD_AC_CUSTOM, ?CUSTOM_ACT_TYPE_MOBILIZE, 1);
        warsoul ->
            lib_counter:increment(RoleId, ?MOD_AC_CUSTOM, ?CUSTOM_ACT_TYPE_MOBILIZE, 2);
        _ ->
            ignore
    end.

% 处理通用事件
handle_event(Role, Event = #event_callback{type_id = ?EVENT_ADD_LIVENESS}) ->
    #event_callback{data = #callback_activity_live{add_live = Add}} = Event,
    update_mobilize_task(Role, activation, Add),
    {ok, Role};
handle_event(Role, #event_callback{type_id = ?EVENT_RECHARGE}) ->
    %% 首充累计
    update_mobilize_task(Role, firstrecharge, 1, true),
    %% 每日首充，非累计
	RoleId = Role#player_status.id,
	case lib_daily:get_count(RoleId, ?MOD_AC_CUSTOM, 32) of
		Count when is_integer(Count), Count =< 0 ->
			update_mobilize_task(Role, dailyrecharge, 1, false),
			lib_daily:increment(RoleId, ?MOD_AC_CUSTOM, 32);
		_ ->
			ignore
	end,
    {ok, Role};
handle_event(Role, #event_callback{type_id = ?EVENT_MONEY_CONSUME, data = Data})  ->
    #callback_money_cost{money_type = MoneyType, cost = Cost} = Data,
    MoneyType == ?TYPE_GOLD andalso update_mobilize_task(Role, goldconsume, Cost, false),
    {ok, Role};
handle_event(Role, #event_callback{type_id = ?EVENT_COMBAT_POWER, data = CallbackData}) ->
    %% 战力变更事件，此时最高战力还没有刷新(用最新战力-历史最高)
    OpenDay = util:get_open_day(),
    case OpenDay of
        ?MOBILIZE_POWER_CALC_DAY ->
            #player_status{mobilize_combat_power = HisCombat} = Role,
            #callback_combat_power_data{
                % old_combat_power = OldCombatPower,
                combat_power = CombatPower
            } = CallbackData,
            case CombatPower > HisCombat of
                true when HisCombat > 0 ->
                    AddPower = CombatPower - HisCombat,
                    update_mobilize_task(Role, combat, max(0, AddPower), false, 1);
                _ ->
                    ignore
            end;
        _ ->
            ignore
    end,
    {ok, Role};
handle_event(Role, #event_callback{type_id = ?EVENT_LV_UP}) ->
    #player_status{figure = Figure} = Role,
    %% 满足等级条件，推送红点
    case lib_custom_act_api:get_open_custom_act_infos(?CUSTOM_ACT_TYPE_MOBILIZE) of
        [_|_] ->
            case is_lv_finish(Figure#figure.lv) of
                true ->
                    send_mobilize_task_info(Role);
                _ ->
                    ignore
            end,
            LvKeys = get_lv_key(Figure#figure.lv),
            case LvKeys of
                [_|_] ->
                    KFun = fun(LvKey) ->
                        update_mobilize_task(Role, LvKey, 1, true)
                           end,
                    lists:map(KFun, LvKeys);
                _ ->
                    ignore
            end;
        _ -> ignore
    end,
    {ok, Role};
handle_event(Role, #event_callback{type_id = ?EVENT_CLIENT_LOGIN_SUCCESS}) ->
    #player_status{figure = Figure, mobilize_combat_power = MobilizePower,
        combat_power = CombatPower, id = RoleId, equipment = StatusEquipment
    } = Role,
    %% 满足等级条件，推送红点
    case lib_custom_act_api:get_open_custom_act_infos(?CUSTOM_ACT_TYPE_MOBILIZE) of
        [_|_] ->
            case is_lv_finish(Figure#figure.lv) of
                true ->
                    send_mobilize_task_info(Role);
                _ ->
                    ignore
            end,
            LvKeys = get_lv_key(Figure#figure.lv),
            case LvKeys of
                [_|_] ->
                    KFun = fun(LvKey) ->
                        update_mobilize_task(Role, LvKey, 1, true)
                           end,
                    lists:map(KFun, LvKeys);
                _ ->
                    ignore
            end;
        _ -> ignore
    end,
    %% 记录当天登录的战力
    OpenDay = util:get_open_day(),
    NewRole =
    case OpenDay of
        ?MOBILIZE_POWER_CALC_DAY ->
            case MobilizePower of
                0 ->
                    Sql = io_lib:format(?SQL_SAVE_MOBILIZE_POWER,
                        [RoleId, CombatPower]),
                    db:execute(Sql),
                    Role#player_status{mobilize_combat_power = CombatPower};
                _ ->
                    Role
            end;
        _ ->
            Role
    end,
    %% 记录初始装备宝石总等级
    case OpenDay of
        ?MOBILIZE_EQUIP_GEM_CALC_DAY ->
            case lib_daily:get_count(Role#player_status.id, ?MOD_AC_CUSTOM, 34) of
                IsRecord when is_integer(IsRecord), IsRecord > 0 -> ignore;
                _ ->
                    lib_daily:set_count(Role#player_status.id, ?MOD_AC_CUSTOM, 34, 1),
                    SumLv = equipment_logic:calc_sum_lv(StatusEquipment#equipment.equipment_series),
                    lib_daily:set_count(Role#player_status.id, ?MOD_AC_CUSTOM, 33, SumLv)
            end;
        _ ->
            ok
    end,
    {ok, NewRole};
handle_event(Role, #event_callback{type_id = ?EVENT_VIP, data = Data}) ->
    #player_status{figure = Figure} = Role,
    case Figure#figure.vip > 0 of
        true ->
            OldVipLv1 =
            case Data of
                {OldVipLv, _, _} -> OldVipLv + 1;
                _ -> 1
            end,
            OldVipLv2 =
            case OldVipLv1 > Figure#figure.vip of
                true -> Figure#figure.vip;
                _ -> OldVipLv1
            end,
            F = fun(TVip, TList) ->
                VipKey = get_vip_key(TVip),
                [VipKey|TList]
                end,
            VipKeyList = lists:foldl(F, [], lists:seq(OldVipLv2, Figure#figure.vip)),
            ForFun = fun(TVipKey) ->
                case is_atom(TVipKey) of
                    true ->
                        update_mobilize_task(Role, TVipKey, 1, true);
                    _ ->
                        ignore
                end end,
            lists:map(ForFun, VipKeyList);
        _ ->
            ignore
    end,
    {ok, Role};
handle_event(Role, _Event) ->
    {ok, Role}.

%% 装备宝石任务
update_mobilize_gem_task(Player, _OldSumLv, NewSumLv) ->
    RoleId = Player#player_status.id,
    OpenDay = util:get_open_day(),
    case OpenDay == ?MOBILIZE_EQUIP_GEM_CALC_DAY of
        true ->
            %% 当天初始等级
            case lib_daily:get_count(RoleId, ?MOD_AC_CUSTOM, 33) of
                Count when is_integer(Count), Count > 0 -> ok;
                _ ->
                    Count = 0
            end,
            case NewSumLv > Count of
                true ->
                    TrueAddValue = max(0, NewSumLv - Count),
                    TrueAddValue > 0 andalso
                        custom_act_mobilize:update_mobilize_task(
                            Player, gems, TrueAddValue, false, 1
                        );
                _ ->
                    ignore
            end;
        _ ->
            ignore
    end,
    ok.

get_lv_key(Lv) ->
    CfgLvs = [70, 90, 100, 110, 120, 130, 135],
    F = fun(CfgLv, TList) ->
        case Lv >= CfgLv of
            true ->
                LvKey = list_to_atom(lists:concat(["lv", CfgLv])),
                case data_custom_mobilize:get_task_type_id(LvKey) of
                    TaskTypeId when is_integer(TaskTypeId), TaskTypeId > 0 ->
                        [LvKey|TList];
                    _ ->
                        TList
                end;
            _ ->
                TList
        end end,
    lists:foldl(F, [], CfgLvs).

get_vip_key(Vip) ->
    VipKey = list_to_atom(lists:concat(["vip", Vip])),
    case data_custom_mobilize:get_task_type_id(VipKey) of
        TaskTypeId when is_integer(TaskTypeId), TaskTypeId > 0 -> VipKey;
        _ -> 0
    end.

is_lv_finish(RoleLv) ->
    OpenDay = util:get_open_day(),
    TypeList = [10,11,12,13,14,15,16],
    F = fun(TaskType, Boolean) ->
        TaskIdList = data_custom_mobilize:get_task_id_list(TaskType),
        F1 = fun(TaskId) ->
            case data_custom_mobilize:get_mobilize_task(TaskType, TaskId) of
                #custom_mobilize_task{gain_con = {lv, Value}, day = StartDay, end_day = EndDay}
                    when RoleLv == Value, StartDay =< OpenDay, OpenDay =< EndDay ->
                    true;
                _ ->
                    false
            end end,
        case lists:any(F1, TaskIdList) of
            true -> true;
            _ -> Boolean
        end end,
    Result = lists:foldl(F, false, TypeList),
    Result.

%% 副本完成
finish_dungeon(RoleID, DunType, DunID)->
    finish_dungeon(RoleID, DunType, DunID,1).
finish_dungeon(RoleID, DunType, DunID,Num)->
    case DunType of
        ?DUNGEON_TYPE_MATERIAL when DunID =:= 1001 ->
            update_mobilize_task(RoleID, cardun, Num);
        _ ->
            ok
    end.

%% 检查是否有进度(硬性条件判断)
%% 首充(首充需要从活动开始时间判定)
check_gain_pro(Role, ActInfo, {StartDay, EndDay}, {recharge,_Value}, TaskTypeId, _TaskStat)->
    #player_status{id=RoleId}=Role,
    #act_info{key = {_, SubType}, stime = ActSTime, etime = ActETime} = ActInfo,
    {_STime, ETime} = task_type_from_start_to_end(SubType, TaskTypeId, StartDay, EndDay, ActSTime, ActETime),
    case lib_recharge_data:get_my_recharge_between(RoleId, ActSTime, ETime) > 0 of
        true ->
            1;
        _ ->
            0
    end;
%% 投资
check_gain_pro(_Role,_ActInfo,_DayInterval,{invest,Value},TaskType,TaskStat)->
    case lists:keyfind(TaskType, #mobilize_task.task_type, TaskStat) of
        #mobilize_task{task_pro = Num} when Num>=Value->
            1;
        _ ->
            0
    end;
%% 0元礼包购买
check_gain_pro(_Role,_ActInfo,_DayInterval,{zerogift,Value},TaskType,TaskStat)->
    case lists:keyfind(TaskType, #mobilize_task.task_type, TaskStat) of
        #mobilize_task{task_pro = Num} when Num>=Value->
            1;
        _ ->
            0
    end;
%% 直购礼包
check_gain_pro(_Role,_ActInfo,_DayInterval,{directbuy,Value},TaskType,TaskStat)->
    case lists:keyfind(TaskType, #mobilize_task.task_type, TaskStat) of
        #mobilize_task{task_pro = Num} when Num>=Value->
            1;
        _ ->
            0
    end;
%% 周卡
check_gain_pro(Role,_ActInfo,_DayInterval,{weekcard,_Value},_TaskType,_TaskStat)->
    #player_status{recharge_act_status = RechargeAct} = Role,
    #recharge_act_status{welfare = Welfare} = RechargeAct,
    ProductIds = [Id || #recharge_goods{product_id = Id} <- Welfare],
    ExistId = lists:foldl(fun(Id, Exist) ->
        case data_recharge:get_product(Id) of
            #base_recharge_product{product_type = 2, product_subtype = 1} ->
                Id;
            _ ->
                Exist
        end
    end, 0, ProductIds),
    case ExistId>0 of
        true->
            1;
        _->
            0
    end;
%% 月卡
check_gain_pro(Role,_ActInfo,_DayInterval,{moncard,_Value},_TaskType,_TaskStat)->
    #player_status{recharge_act_status = RechargeAct} = Role,
    #recharge_act_status{welfare = Welfare} = RechargeAct,
    ProductIds = [Id || #recharge_goods{product_id = Id} <- Welfare],
    ExistId = lists:foldl(fun(Id, Exist) ->
        case data_recharge:get_product(Id) of
            #base_recharge_product{product_type = 2, product_subtype = 2} ->
                Id;
            _ ->
                Exist
        end
    end, 0, ProductIds),
    case ExistId>0 of
        true->
            1;
        _->
            0
    end;
%% 季卡
check_gain_pro(Role,_ActInfo,_DayInterval,{seasoncard,_Value},_TaskType,_TaskStat)->
    #player_status{recharge_act_status = RechargeAct} = Role,
    #recharge_act_status{welfare = Welfare} = RechargeAct,
    ProductIds = [Id || #recharge_goods{product_id = Id} <- Welfare],
    ExistId = lists:foldl(fun(Id, Exist) ->
        case data_recharge:get_product(Id) of
            #base_recharge_product{product_type = 2, product_subtype = 3} ->
                Id;
            _ ->
                Exist
        end
    end, 0, ProductIds),
    case ExistId>0 of
        true->
            1;
        _->
            0
    end;
%% 等级
check_gain_pro(Role,_ActInfo,_DayInterval,{lv,Value},_TaskType,_TaskStat)->
    #player_status{figure = Figure} = Role,
    case Figure#figure.lv >= Value of
        true -> 1;
        _ -> 0
    end;
%% vip
check_gain_pro(Role,_ActInfo,_DayInterval,{vip,Value},_TaskType,_TaskStat)->
    #player_status{figure = Figure} = Role,
    case Figure#figure.vip >= Value of
        true -> 1;
        _ -> 0
    end;
%% 万物宝典
check_gain_pro(_Role,_ActInfo,_DayInterval,{contract,_Value},_TaskType,_TaskStat)->
    #custom_act_data{act_data = ActData} = lib_custom_act_data:custom_act_data(?CUSTOM_ACT_TYPE_CONTRACT, 1),
    case ActData of
        #role_contract{
            pay_contract = IsPay
        } ->
            case IsPay > 0 of
                true -> 1;
                _ -> 0
            end;
        _ ->
            0
    end;
%% 读取不到配置全部设定为达成
check_gain_pro(_Role,_ActInfo,_DayInterval,_,_TaskType,_TaskStat)->
    1.

%% 获得任务FakeID
get_task_fake(SubType,TaskType)->
    case data_custom_mobilize:get_task_fake(SubType,TaskType) of
        [H|_T]->
            H;
        _->
            0
    end.

%% 统计天数范围内完成任务数是否达标
%% 如果是可领取/已领取，状态不变
check_total_state(_, _, _, 2) ->
    2;
check_total_state(_, _, _, 1) ->
    1;
check_total_state(Num, NeedNum, _TypeList, _) ->
    % Total = lists:foldl(fun(Type,Args)->
    %    List = data_custom_mobilize:get_task_id_list(Type),
    %    length(List)+Args
    % end, 0, TypeList),
    case Num >= NeedNum of
        true ->
            1;
        _ ->
            0
    end.

%% @doc 活动派发接口：定制活动开启或者关闭 默认处理
notify_other_module(?CUSTOM_ACT_STATUS_OPEN,_IsKfActType,#act_info{key = {_ActType, SubType}} = ActInfo, Stime, Etime) ->
    lib_custom_act:broadcast_act_info(?CUSTOM_ACT_STATUS_OPEN, [ActInfo]),
    case ActInfo of
        #act_info{trigger_time = _T} ->
            mod_mobilize_mgr:cast({init_fake, SubType, Stime, Etime});
        _ ->
            mod_mobilize_mgr:cast({redo_init_fake, SubType, Stime, Etime}),
            ok
    end;
notify_other_module(ActStatus,_IsKfActType, ActInfo,_Stime, _Etime)
    when ActStatus =:= ?CUSTOM_ACT_STATUS_CLOSE
    orelse ActStatus =:= ?CUSTOM_ACT_STATUS_MANUAL_CLOSE ->
    lib_custom_act:broadcast_act_info(ActStatus, [ActInfo]),
    mod_mobilize_mgr:cast({clean_fake}),
    ok;
notify_other_module(_, _, _, _, _) -> ok.
