%%%-------------------------------------------------------------------
%%% @author liushl
%%% @doc
%%%     秒杀-本服管理 记录玩家订阅/管理活动通知
%%% @end
%%%-------------------------------------------------------------------
-module(seckill_local).
-author("liushl").

-behaviour(gen_server).

-include("custom_act.hrl").
-include("def_module.hrl").
-include("seckill.hrl").
%% API
-export([start_link/0]).

%% gen_server callbacks
-export([init/1,
    handle_call/3,
    handle_cast/2,
    handle_info/2,
    terminate/2,
    code_change/3]).

-define(SERVER, ?MODULE).

-export([
    subscribe_seckill/2,
    somebody_buy_seckill/7,
    seckill_notice/1,
    seckill_round_begin/2,
    apply_cast/1
]).

-record(state, { subscribe = [] }).

%%%===================================================================
%%% API
%%%===================================================================
%% 订阅
%% 玩家离线的时候需要取消订阅
subscribe_seckill(RoleId, Status) ->
    apply_cast({subscribe_seckill, RoleId, Status}).

%% 有人秒杀了
somebody_buy_seckill(SubType, ZoneId, Log, GradeId, IsTv, Round, TvId) ->
    czone:zone_apply_cast(ZoneId,  {?MODULE, apply_cast, [{somebody_buy, SubType, Log, GradeId, IsTv, Round, TvId}]}).

%% 预告场次开启
seckill_notice(SubType) ->
    clusters_center:apply_to_all_node(?MODULE, apply_cast, [{seckill_notice, SubType}]).

%% 通知场次开启了
seckill_round_begin(SubType, Round) ->
    clusters_center:apply_to_all_node(?MODULE, apply_cast, [{seckill_round_begin, SubType, Round}]).

apply_cast(Msg) ->
    gen_server:cast(?MODULE, Msg).
%%--------------------------------------------------------------------
%% @doc
%% Starts the server
%%
%% @end
%%--------------------------------------------------------------------
-spec(start_link() ->
    {ok, Pid :: pid()} | ignore | {error, Reason :: term()}).
start_link() ->
    gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).

%%--------------------------------------------------------------------
%% @private
%% @doc
%% Initializes the server
%%
%% @spec init(Args) -> {ok, State} |
%%                     {ok, State, Timeout} |
%%                     ignore |
%%                     {stop, Reason}
%% @end
%%--------------------------------------------------------------------
-spec(init(Args :: term()) ->
    {ok, State :: #state{}} | {ok, State :: #state{}, timeout() | hibernate} |
    {stop, Reason :: term()} | ignore).
init([]) ->
    {ok, #state{}}.

%%%===================================================================
%%% Logic 
%%%===================================================================
do_handle_call(_Request, _From, State) ->
    io:format("time:[~p], module:~p: do_handle_call unexpect message:~p~n", [erlang:localtime(), ?MODULE, _Request]),
    {reply, ok, State}.

%% 订阅
do_handle_cast({subscribe_seckill, RoleId, Status}, State) ->
    #state{subscribe = Subscribe} = State,
    NewSubscribe =
    case Status of
        1  ->
            case lists:member(RoleId, Subscribe) of
                true  ->
                    Subscribe;
                false ->
                    [RoleId|Subscribe]
            end;
        _  ->
            lists:delete(RoleId, Subscribe)
            
    end,
    {noreply, State#state{subscribe = NewSubscribe}};

%% 有人秒杀了
do_handle_cast({somebody_buy, SubType, Log, GradeId, IsTv, Round, TvId}, State) ->
    #state{subscribe = Subscribe} = State,
    #seckill_buy_log{
        server      = ServerNum,
        name        = Name,
        goods_id    = GoodsId,
        num         = Num
    } = Log,
    case lib_custom_act_api:is_open_act(?CUSTOM_ACT_TYPE_SECKILL, SubType) of
        true ->
            %% 广播给订阅玩家
            {ok, Bin} = pt_331:write(33193, [ServerNum, Name, 0, GoodsId, Num, GradeId, Round, TvId]),
            [
                lib_server_send:send_to_uid(RoleId, Bin)|| RoleId <- Subscribe
            ],
            IsTv == 1 andalso
                lib_chat:send_TV({all}, ?MOD_AC_CUSTOM, TvId, [ServerNum, Name, GoodsId, Num]);
        false ->
            ok
    end,
    {noreply, State};

%% 预告通知
do_handle_cast({seckill_notice, SubType}, State) ->
    case lib_custom_act_api:is_open_act(?CUSTOM_ACT_TYPE_SECKILL, SubType) of
        true ->
            lib_chat:send_TV({all}, ?MOD_AC_CUSTOM, 17, []);
        false ->
            ok
    end,
    {noreply, State};

%% 场次开启
do_handle_cast({seckill_round_begin, SubType, Round}, State) ->
    case lib_custom_act_api:is_open_act(?CUSTOM_ACT_TYPE_SECKILL, SubType) of
        true ->
            RoundCfg = data_custom_act:get_seckill_round(),
            case lists:keyfind(Round, 1, RoundCfg) of
                {Round, _Time, _Duration, Label} when Label > 1 ->
                    lib_chat:send_TV({all}, ?MOD_AC_CUSTOM, 18, []);
                _ ->
                    ok
            end,
            {ok, Bin} = pt_331:write(33194, [Round]),
            lib_server_send:send_to_all(Bin);
        false ->
            ok
    end,
    {noreply, State};

do_handle_cast(_Request, State) ->
    io:format("time:[~p], module:~p: handle_cast unexpect message:~p~n", [erlang:localtime(), ?MODULE, _Request]),
    {noreply, State}.

do_handle_info(_Info, State) ->
    io:format("time:[~p], module:~p: handle_info unexpect message:~p~n", [erlang:localtime(), ?MODULE, _Info]),
    {noreply, State}.


%%--------------------------------------------------------------------
%% @private
%% @doc
%% Handling call messages
%%
%% @end
%%--------------------------------------------------------------------
-spec(handle_call(Request :: term(), From :: {pid(), Tag :: term()},
    State :: #state{}) ->
    {reply, Reply :: term(), NewState :: #state{}} |
    {reply, Reply :: term(), NewState :: #state{}, timeout() | hibernate} |
    {noreply, NewState :: #state{}} |
    {noreply, NewState :: #state{}, timeout() | hibernate} |
    {stop, Reason :: term(), Reply :: term(), NewState :: #state{}} |
    {stop, Reason :: term(), NewState :: #state{}}).
handle_call(Msg, From, State) ->
    try
        do_handle_call(Msg, From, State)
    catch _:_Error ->
        io:format("[~p]~nhandle_call Msg:~p~n Error:~p~n ~p~n", [erlang:localtime(), Msg, _Error, erlang:get_stacktrace()]),
        {reply, error, State}
    end.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Handling cast messages
%%
%% @end
%%--------------------------------------------------------------------
-spec(handle_cast(Request :: term(), State :: #state{}) ->
    {noreply, NewState :: #state{}} |
    {noreply, NewState :: #state{}, timeout() | hibernate} |
    {stop, Reason :: term(), NewState :: #state{}}).
handle_cast(Msg, State) ->
    try
        do_handle_cast(Msg, State)
    catch _:_Error:Stack ->
        io:format("[~p]~nhandle_cast Msg:~p~n Error:~p~n ~p~n", [erlang:localtime(), Msg, _Error, Stack]),
        {noreply, State}
    end.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Handling all non call/cast messages
%%
%% @spec handle_info(Info, State) -> {noreply, State} |
%%                                   {noreply, State, Timeout} |
%%                                   {stop, Reason, State}
%% @end
%%--------------------------------------------------------------------
-spec(handle_info(Info :: timeout() | term(), State :: #state{}) ->
    {noreply, NewState :: #state{}} |
    {noreply, NewState :: #state{}, timeout() | hibernate} |
    {stop, Reason :: term(), NewState :: #state{}}).
handle_info(Msg, State) ->
    try
        do_handle_info(Msg, State)
    catch _:_Error ->
        io:format("[~p]~nhandle_info Msg:~p~n Error:~p~n ~p~n", [erlang:localtime(), Msg, _Error, erlang:get_stacktrace()]),
        {noreply, State}
    end.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% This function is called by a gen_server when it is about to
%% terminate. It should be the opposite of Module:init/1 and do any
%% necessary cleaning up. When it returns, the gen_server terminates
%% with Reason. The return value is ignored.
%%
%% @spec terminate(Reason, State) -> void()
%% @end
%%--------------------------------------------------------------------
-spec(terminate(Reason :: (normal | shutdown | {shutdown, term()} | term()),
    State :: #state{}) ->
    term()).
terminate(_Reason, _State) ->
    ok.

%%--------------------------------------------------------------------
%% @private
%% @doc
%% Convert process state when code is changed
%%
%% @spec code_change(OldVsn, State, Extra) -> {ok, NewState}
%% @end
%%--------------------------------------------------------------------
-spec(code_change(OldVsn :: term() | {down, term()}, State :: #state{},
    Extra :: term()) ->
    {ok, NewState :: #state{}} | {error, Reason :: term()}).
code_change(_OldVsn, State, _Extra) ->
    {ok, State}.

%%%===================================================================
%%% Internal functions
%%%===================================================================
