%% ---------------------------------------------------------------------------
%% @doc 定制活动全服记录进程
%% @author zhaoyu
%% @since  2019-05-11
%% ---------------------------------------------------------------------------
-module(mod_custom_act_log).

-behaviour(gen_server).

%% API
-export([
        start_link/0
        ,call/1                     %% call本进程
        ,cast/1                     %% cast本进程
        ,info/1                     %% 给进程发送消息
    ]).

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

-include("common.hrl").
-include("custom_act.hrl").
-include("sakura_gift.hrl").
-include("turntable.hrl").

%% 进程#state{}
-record(state, {
}).


%% ---------------------------------------------------------------------------
%% @doc Starts the server
-spec start_link() -> {ok, Pid} | ignore | {error, Error} when
    Pid :: pid(),
    Error :: term().
%% ---------------------------------------------------------------------------
start_link() ->
    gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).


%% ---------------------------------------------------------------------------
%% @doc call进程
-spec call(Msg) -> term() | {error, Reason} when
    Msg     :: term(),
    Reason  :: any().
%% ---------------------------------------------------------------------------
call(Msg) ->
    try gen_server:call(?MODULE, Msg) of
    Reply -> Reply
    catch Class:Reason ->
        Error = {Class, Reason, erlang:get_stacktrace()},
        ?ERR("~w:handle_cast error:~p~n", [?MODULE, Error]),
        {error, Reason}
    end.


%% ---------------------------------------------------------------------------
%% @doc cast进程
-spec cast(Msg) -> ok when
    Msg     :: term().
%% ---------------------------------------------------------------------------
cast(Msg) ->
    gen_server:cast(?MODULE, Msg).


%% ---------------------------------------------------------------------------
%% @doc 给进程发送消息
-spec info(Msg) -> ok when
    Msg     :: term().
%% ---------------------------------------------------------------------------
info(Msg) ->
    erlang:send(?MODULE, Msg).


%% ---------------------------------------------------------------------------
%% @doc Initializes the server
-spec init(Args) ->
    {ok, State}
    | {ok, State, Timeout}
    | ignore
    | {stop, Reason} when
    Args    :: term() ,
    State   :: #state{},
    Timeout :: non_neg_integer() | infinity,
    Reason  :: term().
%% ---------------------------------------------------------------------------
init([]) ->
    process_flag(trap_exit, true),
    erlang:send_after(30*1000, self(), {init_sakura_gift_log}),
    erlang:send_after(3000, self(), load_turntable_record),
    {ok, #state{}}.


%% ---------------------------------------------------------------------------
%% @doc Handling call messages
-spec handle_call(Request, From, State) ->
    {reply, Reply, State}
    | {reply, Reply, State, Timeout}
    | {noreply, State}
    | {noreply, State, Timeout}
    | {stop, Reason, Reply, State}
    | {stop, Reason, State} when
    Request :: term(),
    From :: {pid(),Tag}, Tag::any(),
    State :: #state{},
    Reply :: term(),
    State :: #state{},
    Timeout :: non_neg_integer() | infinity.
%% ---------------------------------------------------------------------------
handle_call(_Request, _From, State) ->
    Reply = ok,
    {reply, Reply, State}.


%% ---------------------------------------------------------------------------
%% @doc Handling cast messages
-spec handle_cast(Msg, State) ->
    {noreply, State}
    | {noreply, State, Timeout}
    | {stop, Reason, State} when
    Msg :: term(),
    State :: #state{},
    Timeout :: non_neg_integer() | infinity,
    Reason :: term().
%% ---------------------------------------------------------------------------
handle_cast(Msg, State) ->
    try handle_cast2(Msg, State) of
        Result ->
            Result
    catch Class:Reason ->
        Error = {Class, Reason, erlang:get_stacktrace()},
        ?ERR("~w:handle_cast error:~p~n", [?MODULE, Error]),
        {noreply, State}
    end.

%% 招财猫记录
handle_cast2({lucky_cat_log, Type, SubType, Log}, State) ->
    Key = lucky_cat_log_key(Type, SubType),
    LogList = case erlang:get(Key) of
        List when is_list(List) -> List;
        _ -> []
    end,
    MaxLen = 30,
    LogList2 = lists:sublist([Log | LogList], MaxLen),
    erlang:put(Key, LogList2),
    {noreply, State};
handle_cast2({send_lucky_cat_log, Type, SubType, Sid}, State) ->
    Key = lucky_cat_log_key(Type, SubType),
    LogList = case erlang:get(Key) of
        List when is_list(List) -> List;
        _ -> []
    end,
    {ok, BinData} = pt_332:write(33222, [Type, SubType, LogList]),
    lib_server_send:send_to_sid(Sid, BinData),
    {noreply, State};

%% 惊喜红包记录
handle_cast2({red_packet_log, Type, SubType, Log}, State) ->
    Key = red_packet_log_key(Type, SubType),
    LogList = case erlang:get(Key) of
                  List when is_list(List) -> List;
                  _ -> []
              end,
    MaxLen = case lib_custom_act_util:keyfind_act_condition(Type, SubType, log_num) of
                 {log_num, LogNum} -> LogNum;
                 _ -> 10
             end,
    LogList2 = lists:sublist([Log | LogList], MaxLen),
    erlang:put(Key, LogList2),
    {noreply, State};
handle_cast2({send_red_packet_log, Type, SubType, Sid}, State) ->
    Key = red_packet_log_key(Type, SubType),
    LogList = case erlang:get(Key) of
                  List when is_list(List) -> List;
                  _ -> []
              end,
    surprise_red_packet:send_red_packet_log(SubType, LogList, Sid),
    {noreply, State};

%% 源樱之礼记录
handle_cast2({sakura_gift_log, Type, SubType, Log}, State) ->
    Key = sakura_gift_log_key(Type, SubType),
    LogList = case erlang:get(Key) of
                  List when is_list(List) -> List;
                  _ -> []
              end,
    MaxLenRare    = ?LOG_LEN_SERVER_RARE,
    MaxLenExtreme = ?LOG_LEN_SERVER_EXTREME,
    LogTag = Log#sakura_server_log.tag,
    MaxLen = case LogTag of
                 ?SAKURA_RARE_REWARD -> MaxLenRare;
                 _ -> MaxLenExtreme
             end,
    LastLog = case LogList of
                  [First|_] -> First;
                  _ -> #sakura_server_log{}
              end,
    #sakura_server_log{key = LastKey} = LastLog,
    Log1 = Log#sakura_server_log{key = LastKey + 1},
    SplitF = fun(#sakura_server_log{tag = Tag} = TLog, {TList1, TList2}) ->
        case Tag of
            ?SAKURA_RARE_REWARD -> {[TLog|TList1], TList2};
            ?SAKURA_EXTREME_REWARD -> {TList1, [TLog|TList2]};
            _ -> {TList1, TList2}
        end end,
    {RareLogList, ExtremeLogList} = lists:foldr(SplitF, {[], []}, LogList),
    case LogTag of
        ?SAKURA_RARE_REWARD ->
            {LogList2, DropList} = ulists:split(MaxLen, [Log1 | RareLogList]),
            LogList3 = LogList2 ++ ExtremeLogList;
        _ ->
            {LogList2, DropList} = ulists:split(MaxLen, [Log1 | ExtremeLogList]),
            LogList3 = LogList2 ++ RareLogList
    end,
    sakura_gift:save_server_log_to_db(SubType, Log1),
    DropF = fun(#sakura_server_log{key = DropKey}) ->
        DropKey > 0 andalso sakura_gift:del_server_log_from_db(SubType, DropKey)
    end,
    lists:map(DropF, DropList),
    erlang:put(Key, LogList3),
    {noreply, State};
handle_cast2({send_sakura_gift_log, Type, SubType, RoleId, RoleName}, State) ->
    Key = sakura_gift_log_key(Type, SubType),
    LogList = case erlang:get(Key) of
                  List when is_list(List) ->
                      List;
                  _ -> []
              end,
    sakura_gift:send_server_log(SubType, LogList, RoleId, RoleName),
    {noreply, State};
handle_cast2({clean_sakura_gift_log, Type, SubType}, State) ->
    Key = sakura_gift_log_key(Type, SubType),
    erlang:put(Key, []),
    {noreply, State};

%% 发送全服抽奖记录
handle_cast2({send_lottery_record, Sid, SubType}, State) ->
    Key = turntable_log_key(SubType),
    LogList = case erlang:get(Key) of
                  List when is_list(List) -> List;
                  _ -> []
              end,
    lib_server_send:send_to_sid(Sid, pt_335, 33505, [SubType, LogList]),
    {noreply, State};

%% 活动结束清理数据
handle_cast2({clear_turntable_data, SubType}, State) ->
    Key = turntable_log_key(SubType),
    erlang:erase(Key),
    {noreply, State};

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


%% ---------------------------------------------------------------------------
%% @doc Handling all non call/cast messages
-spec handle_info(Info, State) ->
    {noreply, State}
    | {noreply, State, Timeout}
    | {stop, Reason, State} when
    Info :: term(),
    State :: #state{},
    Timeout :: non_neg_integer() | infinity,
    Reason :: term().
%% ---------------------------------------------------------------------------
handle_info(Info, State) ->
    try handle_info2(Info, State) of
        Result ->
            Result
    catch Class:Reason ->
        Error = {Class, Reason, erlang:get_stacktrace()},
        ?ERR("~w:handle_cast error:~p~n", [?MODULE, Error]),
        {noreply, State}
    end.


%% ---------------------------------------------------------------------------
%% @doc Handling all non call/cast messages
-spec handle_info2(Info, State) ->
    {noreply, State}
    | {noreply, State, Timeout}
    | {stop, Reason, State} when
    Info :: term(),
    State :: #state{},
    Timeout :: non_neg_integer() | infinity,
    Reason :: term().
%% ---------------------------------------------------------------------------
handle_info2({init_sakura_gift_log}, State) ->
    SubTypeList = lib_custom_act_util:get_open_subtype_list(?CUSTOM_ACT_TYPE_SAKURA_GIFT),
    F = fun(#act_info{key = {_, SubType}}) ->
                init_sakura_gift_log(SubType);
            (_) -> ignore
    end,
    lists:map(F, SubTypeList),
    {noreply, State};

handle_info2({record_lottery_info, RoleId, RoleName, SubType, RcList, TvList}, State) ->
    [begin
         if
             Tag == 6 ->
                 lib_chat:send_TV({all}, 331, 44, [RoleName, GoodsId, Num]);
             true ->
                 lib_chat:send_TV({all}, 331, 43, [RoleName, GoodsId, Num])
         end
     end || {GoodsId, Num, Tag} <- TvList],
    Key = turntable_log_key(SubType),
    LogList = case erlang:get(Key) of
                  List when is_list(List) -> List;
                  _ -> []
              end,
    NLogList = lists:sublist(RcList ++ LogList, 30),
    put(Key, NLogList),
    {ok, BinData} = pt_335:write(33505, [SubType, NLogList]),
    lib_server_send:send_to_uid(RoleId, BinData),
    {noreply, State};

%% 加载大奖记录
handle_info2(load_turntable_record, State) ->
    SubList = lib_custom_act_util:get_open_subtype_list(?CUSTOM_ACT_TYPE_TURNTABLE),
    F = fun(SubType) ->
        % 取30条获奖记录
        Sql = io_lib:format(?SQL_SELECT_TURNTABLE_LOTTERY_RECORD, [SubType]),
        case db:get_all(Sql) of
            Data = [_|_] ->
                LogList = [{Name, GoodsId, Num} || [Name, GoodsId, Num] <- Data];
            _ ->
                LogList = []
        end,
        Key = turntable_log_key(SubType),
        put(Key, LogList)
        end,
    [F(SubType) || #act_info{key = {_, SubType}} <- SubList],
    {noreply, State};

handle_info2(_Info, State) ->
    {noreply, State}.


%% ---------------------------------------------------------------------------
%% @doc called by a gen_server when it is about to terminate
-spec terminate(Reason, State) -> ok when
    Reason :: term(),
    State :: #state{}.
%% ---------------------------------------------------------------------------
terminate(_Reason, _State) ->
    ok.


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

init_sakura_gift_log(SubType) ->
    sakura_gift:init_server_log(SubType),
    ok.

lucky_cat_log_key(Type, SubType) ->
    {lucky_cat_log, Type, SubType}.

red_packet_log_key(Type, SubType) ->
    {red_packet_log, Type, SubType}.

sakura_gift_log_key(Type, SubType) ->
    {sakura_gift_log, Type, SubType}.

turntable_log_key(SubType) ->
    {turntable_log_key, SubType}.


