%%-----------------------------------------------------------------------------
%% module  :       mod_cgwar_ctrl
%% @author  :      zmh
%% Created :       2020-07-29
%% description:    跨服帮战时间管理
%%-----------------------------------------------------------------------------
-module(mod_cgwar_ctrl).

-include("errcode.hrl").
-include("common.hrl").
-include("def_module.hrl").
-include("predefine.hrl").
-include("cross_guild_war.hrl").

-export ([init/1, handle_call/3, handle_cast/2, handle_info/2, code_change/3, terminate/2]).
-export ([
    start_link/0,
    cast/1,
    gm_start/1,
    sync_cur_state/1,
    get_valid_time/1,
    clean_data/0,
    calc_state/0
]).

gm_start(Time) ->
    gen_server:cast(?MODULE, {gm_start,Time}).

cast(Msg) ->
    gen_server:cast(?MODULE, Msg).

sync_cur_state(Node)->
    gen_server:cast(?MODULE, {sync_cur_state, Node}).

clean_data()->
    ets:delete_all_objects(?CGW_CAN_JOIN_ETS).

%% API
start_link() ->
    gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).

init([]) ->
   {Msg,S,TimeOut} = calc_state(),
   Ref = erlang:send_after(TimeOut*1000,self(),Msg),
   State = #cgwar_time_mgr{
        state = S,
        ref   = Ref,
        etime = utime:unixtime()+TimeOut
    },
    erlang:send_after(10000,self(),sync_to_cgw_mgr),
    {ok, State}.

handle_call(Msg, From, State) ->
    case catch do_handle_call(Msg, From, State) of
        {'EXIT', Error} ->
            ?ERR("handle_call error: ~p~nMsg=~p~n", [Error, Msg]),
            {reply, error, State};
        Return  ->
            Return
    end.

handle_cast(Msg, State) ->
    case catch do_handle_cast(Msg, State) of
        {'EXIT', Error} ->
            ?ERR("handle_cast error: ~p~nMsg=~p~n", [Error, Msg]),
            {noreply, State};
        Return  ->
            Return
    end.

handle_info(Info, State) ->
    case catch do_handle_info(Info, State) of
        {'EXIT', Error} ->
            ?ERR("handle_info error: ~p~nInfo=~p~n", [Error, Info]),
            {noreply, State};
        Return  ->
            Return
    end.

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

terminate(_Reason, _State) ->
    ?ERR("~p is terminate:~p", [?MODULE, _Reason]),
    ok.

do_handle_call(_Msg, _From, State) ->
    {reply, ok, State}.

do_handle_cast({sync_cur_state, Node}, State) ->
    clusters_center:apply_cast(Node, cross_guild_war_local, sync_cur_state, [State,false]),
    {noreply, State};

%%越过idle期  直接进入报名期
%%Time为0 则表示推动进入下一个阶段
do_handle_cast({gm_start,0},State)->
    #cgwar_time_mgr{state=CurState,ref=Ref}=State,
    util:cancel_timer(Ref),
    Now = utime:unixtime(),
    case CurState of
        ?CGW_ST_IDLE-> %%
            NRef = erlang:send_after(5000,self(),{enter_sign,600}),
            NState = State#cgwar_time_mgr{ref=NRef,etime=Now+5};
        ?CGW_ST_SIGN->
            NRef = erlang:send_after(5000,self(),{enter_support,600}),
            NState = State#cgwar_time_mgr{ref=NRef,etime=Now+5};
        ?CGW_ST_SUPPORT-> %%
            NRef = erlang:send_after(5000,self(),{enter_battle,900+3}),
            NState = State#cgwar_time_mgr{ref=NRef,etime=Now+5};
        ?CGW_ST_PK-> %%提前通知战场结束
            cross_guild_war_mgr:gm_stop(),
            NRef = erlang:send_after(5000,self(),enter_over),
            NState = State#cgwar_time_mgr{ref=NRef,etime=Now+5};
        ?CGW_ST_OVER->
            NRef = erlang:send_after(5000,self(),{enter_sign,600}),
            NState = State#cgwar_time_mgr{ref=NRef,etime=Now+5};
        _->
            NState = State
    end,
    sync_all_state(NState),
    {noreply,NState};
do_handle_cast({gm_start,Time},State)->
    #cgwar_time_mgr{ref=Ref}=State,
    util:cancel_timer(Ref),
    cross_guild_war_mgr:gm_stop(),
    NRef   = erlang:send_after(Time*1000,self(),enter_sign),
    NState = State#cgwar_time_mgr{state=?CGW_ST_IDLE,ref=NRef,etime=utime:unixtime()+Time},
    sync_all_state(NState),
    {noreply,NState};

do_handle_cast(_Msg, State) ->
    {noreply, State}.

%%idle结束 进入报名期
do_handle_info(enter_sign,State)->
    SignT = get_valid_time(sign),
    do_handle_info({enter_sign,SignT},State);
do_handle_info({enter_sign,SignT},State)->
    Ref = erlang:send_after(SignT*1000,self(),enter_support),
    Etime = utime:unixtime()+SignT,
    NState = State#cgwar_time_mgr{state=?CGW_ST_SIGN,ref=Ref,etime=Etime},
    camp_war_mgr:notice_camp_war_ret(),
    sync_all_state(NState),
    {noreply, NState};

do_handle_info(enter_support,State)->
    SupportT = get_valid_time(support)-get_valid_time(sign),
    do_handle_info({enter_support,SupportT},State);
do_handle_info({enter_support,SupportT},State)->
    Ref = erlang:send_after(SupportT*1000,self(),enter_battle),
    Etime = utime:unixtime()+SupportT,
    NState = State#cgwar_time_mgr{state=?CGW_ST_SUPPORT,ref=Ref,etime=Etime},
    cross_guild_war_mgr:enter_support(?CGW_ST_SUPPORT),
    sync_all_state(NState),
    {noreply, NState};

%%进入活动
do_handle_info(enter_battle,State)->
    BattleT  = get_valid_time(battle)+3,
    do_handle_info({enter_battle,BattleT},State);
do_handle_info({enter_battle,BattleT},State)->
    Etime = utime:unixtime()+BattleT,
    Ref = erlang:send_after(BattleT*1000,self(),enter_over),
    NState = State#cgwar_time_mgr{state=?CGW_ST_PK,ref=Ref,etime=Etime},
    cross_guild_war_mgr:enter_battle(?CGW_ST_PK,Etime-3),
    sync_all_state(NState),
    {noreply, NState};

%%结束
do_handle_info(enter_over,State)->
    % Remain = max(86400-utime:get_seconds_from_midnight(),10),
    NowTime = utime:unixtime(),
    Remain = max(utime:tomorrow() - NowTime, 10),
    Ref    = erlang:send_after(Remain*1000,self(),enter_idle),
    Etime  = NowTime + Remain,
    NState = State#cgwar_time_mgr{state=?CGW_ST_OVER,ref=Ref,etime=Etime},
    cross_guild_war_mgr:enter_over(?CGW_ST_OVER),
    sync_all_state(NState),
    {noreply,NState};


%%close结束 进入idle
do_handle_info(enter_idle,State)->
    {Msg,S,TimeOut} = calc_state(),
    Ref = erlang:send_after(TimeOut*1000,self(),Msg),
    NState = State#cgwar_time_mgr{
        state=S,
        ref=Ref,
        etime=utime:unixtime()+TimeOut
    },
    sync_all_state(NState),
    {noreply, NState};

do_handle_info(sync_to_cgw_mgr,State)->
    #cgwar_time_mgr{state=CurS,etime=ETime}=State,
    TimeOut = max(ETime-utime:unixtime(),1),
    cross_guild_war_mgr:cast({sync_to_cgw_mgr,CurS,TimeOut}),
    {noreply,State};

do_handle_info(_Msg, State) ->
    {noreply, State}.


%%所有节点同步状态
sync_all_state(State)->
    clusters_center:apply_to_all_node(cross_guild_war_local, sync_cur_state, [State,true]).


%%计算开放 0idle1报名2活动3结束
%%子状态1可应援
calc_state()->
    NowTime = utime:unixtime(),
    #cross_guild_war_config{
        week_list = WeekList
        ,support_period = {SupportStartHms, SupportEndHms}
        ,sign_up_period = {SignUpStartHms, SignUpEndHms}
    } = data_cross_guild_war:get_cross_guild_war_config(),
    UnixDate = utime:unixdate(NowTime),
    NowSeconds = NowTime - UnixDate,
    Week = utime:day_of_week(NowTime),
    IsToday = lists:member(Week, WeekList),
    SignUpStartSeconds = to_seconds(UnixDate,SignUpStartHms),
    SignUpEndSeconds = to_seconds(UnixDate,SignUpEndHms),
    SupportStartSeconds = to_seconds(UnixDate,SupportStartHms),
    SupportEndSeconds = to_seconds(UnixDate,SupportEndHms),
    if
        not IsToday -> %% 今天不开活动
            {enter_idle,?CGW_ST_IDLE, utime:tomorrow(UnixDate) + 1-NowTime};
        NowSeconds < SignUpStartSeconds -> %%准备进入报名
            {enter_sign,?CGW_ST_IDLE,UnixDate + SignUpStartSeconds-NowTime};
        NowSeconds >= SignUpStartSeconds andalso NowSeconds < SignUpEndSeconds ->
            {enter_support,?CGW_ST_SIGN,UnixDate + SignUpEndSeconds-NowTime}; %%报名期间 准备应援
        NowSeconds >= SupportStartSeconds andalso NowSeconds < SupportEndSeconds ->
            {enter_battle,?CGW_ST_SUPPORT,UnixDate + SupportEndSeconds-NowTime}; %%应援期间 准备战斗
        true ->
            {enter_idle,?CGW_ST_IDLE,utime:tomorrow(UnixDate) + 1-NowTime}
    end.

%%计算有效时间
get_valid_time(Type)->
    #cross_guild_war_config{
        sign_up_period = {SignUpStartHms, SignUpEndHms}
        ,support_period = {SupportStartHms, SupportEndHms}
        ,battle_period = {BattleStartHms, BattleEndHms}
    } = data_cross_guild_war:get_cross_guild_war_config(),
    UnixDate = utime:unixdate(),
    case Type of
        sign->
            SignUpStartSeconds = to_seconds(UnixDate,SignUpStartHms),
            SignUpEndSeconds = to_seconds(UnixDate,SignUpEndHms),
            SignUpEndSeconds-SignUpStartSeconds;
        support->
            SupportStartSeconds = to_seconds(UnixDate,SupportStartHms),
            SupportEndSeconds = to_seconds(UnixDate,SupportEndHms),
            SupportEndSeconds-SupportStartSeconds;
        battle->
            BattleStartSeconds = to_seconds(UnixDate,BattleStartHms),
            BattleEndSeconds = to_seconds(UnixDate,BattleEndHms),
            BattleEndSeconds-BattleStartSeconds
    end.


to_seconds(UnixDate,{H, M, S}) ->
    utime:unixtime({H, M, S})-UnixDate.
