%% ---------------------------------------------------------------------------
%% @doc timer_midnight
%% @author ming_up@foxmail.com
%% @since  2016-09-18
%% @deprecated 00:00:01执行的定时器
%% ---------------------------------------------------------------------------
-module(timer_midnight).

-include ("common.hrl").
-include ("daily.hrl").
-include ("def_cache.hrl").

-export([start_link/0, handle/0]).
-export([init/1, callback_mode/0, handle_event/4, terminate/3, code_change/4]).

handle() ->
    NowTime = utime:unixtime(),
    ClsType = config:get_cls_type(),
    do_handle(ClsType),
    lib_log_api:log_server_daily_clear(?TWELVE, NowTime, utime:unixtime()),
    ok.

%% 游戏服handle
do_handle(ClsType = ?NODE_GAME) ->
    %% **************************************************
    %% M:F(RewardDelaySec) -> Res when
    %%     DelaySec  :: integer(), DelaySec叠服延时(秒)
    %%     Res       :: term().
    %% Note:
    %% 1.执行接口需要显式添加“DelaySec”叠服延时实参
    %% 2.各执行接口添加的DelaySec，从上往下依次顺序递增
    %% Usage:
    %% 1.rank:award(0)
    %% 发放排行榜奖励：即时清理榜单，延时发放奖励
    %% **************************************************

    %% 周几触发
    Week = utime:day_of_week(),
    week_handle(ClsType, Week),

    %% 每天0点触发
    mod_daily:daily_clear(?TWELVE),
    mod_cache:refresh(?CACHE_REFRESH_TWELVE, 0),
    %% 帮派刷新
    mod_guild:day_clear(?TWELVE, 3),
    %% 日常刷新
    mod_act_join:daily_clear(0),
    %% 冲榜活动刷新
    mod_rush_rank:day_clear(30),
    %% 通用榜单结算
    mod_common_rank:day_clear(60),
    %% 特惠商城清理每日购买数量
    mod_limit_buy:day_clear(30),
    mod_smashed_egg:daily_clear(0),
    %% 玩家公会信息刷新
    lib_guild:daily_clear(?TWELVE),
    %% 拍卖清理
    mod_auction:daily_clear(0),
    lib_role_drum:daily_clear(0),
    %% 每日战力提升
    lib_daily_power_up:power_update(),
    %% 每日活跃度
    lib_activitycalen:daily_clear(0),
    %% 社团采集数据刷新
    guild_collect_mgr:daily_clear(),
    %% 宠物副本排行榜奖励
    mod_dun_pet_rank:midnight_refresh(),
    mod_custom_act:day_trigger(?TWELVE, 0),
    %% 触发跨服主城开放检测通知
    czone_api:check_notice_city_state(),
    %% 社交票券
    relation_coupon:daily_clear(),
    lib_common_rank_api:daily_clear(),

    %%全民动员进度
    mod_mobilize_mgr:daily_log(),
    %% 物品转换检测通知
    mod_convert_mgr:daily_refresh(),
    %% 本地团战检测
    camp_war_mgr:check_act_time(),
    %% 靓丽大赛
    beauty_contest:zero_clock(),
    ok;

%% 跨服handle
do_handle(?NODE_CENTER) ->
    Week = utime:day_of_week(),
    week_handle(?NODE_CENTER, Week),

    %% 要执行的代码写在下面
    camp_war_mgr:check_act_time(),
    beauty_contest:zero_clock(Week),
    seckill_center:seckill_zero_time(),
    mod_vie_rank_center:zero_clock(),
    cross_rank_mgr:zero_clock(),
    ok;

do_handle(ClsType) ->
    ?ERR("unkown cls_type:~p", [ClsType]),
    ok.

%% 游戏服星期一0点handle
week_handle(?NODE_GAME, 1)->
    %% 周次数清理
    mod_week:week_clear_zero(),
    %% 公会任务清理
    lib_task:daily_clear(?TWELVE, 0),
    %% 世界BOSS
    world_boss_mgr:week_clear_zero(),
    %% 守卫信标本服支援榜
    guard_dun_assist_local:weekly_reset(),
    ok;

%% 跨服星期一0点handle
week_handle(?NODE_CENTER, 1)->
    god_dun_rank_mgr:daily_reset(),
    ok;

week_handle(_ClsType, _Day) ->
    ok.

%% 定时器启动
start_link() ->
    gen_statem:start_link({local, ?MODULE}, ?MODULE, [], []).

callback_mode()->
    handle_event_function.

init([]) ->
    {Date, _} = calendar:local_time(),
    {_, _, Time} = get_next_time(Date),
    Ref = erlang:send_after(Time*1000, self(), 'do'),
    {ok, timeout, {Ref, Date}}.

handle_event(Type, Msg, StateName, State)->
    case catch do_handle_event(Type, Msg, StateName, State) of
        {'EXIT', _R} ->
            ?ERR("handle_exit_error:~p~n", [[Type, Msg, StateName, _R]]),
            {keep_state, State};
        Reply ->
            Reply
    end.

terminate(_Reason, _StateName, _State) ->
    ok.

code_change(_OldVsn, StateName, Status, _Extra) ->
    {ok, StateName, Status}.


%% ======================================= privite function ===========================================

get_next_time(LastExecDate) ->
    % {Date, {H,Min,S}} = calendar:local_time(),
    % PassTime = H*3600 + Min*60 + S,
    % case LastExecDate of
    %     Date -> {false, Date, ?ONE_DAY_SECONDS+1 - PassTime};
    %     _    -> {true,  Date, ?ONE_DAY_SECONDS+1 - PassTime}
    % end.
    NowTime = utime:unixtime(),
    NextMidnight = utime:tomorrow(NowTime),
    {Date, _} = utime:unixtime_to_localtime(NowTime),
    NeedExec = LastExecDate =/= Date,
    {NeedExec, Date, NextMidnight + 1 - NowTime}.

do_handle_event(info, 'do', timeout, {ORef, LastExecDate})->
    util:cancel_timer(ORef),
    ?INFO("midnight start", []),
    {IsExec, Date, Time} = get_next_time(LastExecDate),
    Ref = erlang:send_after(Time*1000, self(), 'do'),
    case IsExec of
        true ->
            case catch handle() of
                ok -> skip;
                Error ->  ?ERR("handle_error:~p", [Error])
            end;
        false -> skip
    end,
    ?INFO("midnight end is_exec =~p, last_date=~w, now_date=~w, next_time =~w ", [IsExec, LastExecDate, Date, Time]),
    {next_state, timeout, {Ref, Date}};

do_handle_event(_Type, _Msg, _StateName, State) ->
    ?PRINT("no match :~p~n", [[_Type, _Msg, _StateName]]),
    {keep_state, State}.
