%%%-------------------------------------------------------------------
%%% author : ljy
%%% desc   : 防沉迷数据上传
%%% Time   : 2021.03.30
%%%-------------------------------------------------------------------
-module(mod_prevent_addiction).
-author("ljy").

%% API
-export([start_link/0,upload_prevent_addiction_data/2]).

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

-include("common.hrl").
-include("def_module.hrl").
-include("errcode.hrl").
-include("predefine.hrl").
-include("server.hrl").
-include("figure.hrl").
-include("chat.hrl").
-include("game_vsn.hrl").

-define(MONITOR_URL_SUYOU, "http://tracking.xianyouwan.com/fcm/action?").

-define(SECRET_KEY, "fFL@a^uGE1hC4gxSp!%KnluL0BMZo$lb").

-define(WAIT_REPONSE, 0).
-define(RECV_REPONSE, 1).

%%%===================================================================
%%% API
%%%===================================================================

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

%% 上传防沉迷数据
upload_prevent_addiction_data(Player, Type) ->
    #player_status{accname = AccName, id = RoleId, server_id = SerId, source = Source, figure = #figure{name = RoleName}} = Player,
    if
        is_binary(Source) ->
            Index = string:str(binary_to_list(Source), "suyou"),
            if
                Index > 0 ->
                    gen_server:cast(?MODULE, {'upload_prevent_addiction_data', AccName, SerId, RoleId, RoleName, self(), Type, Source});
                true ->
                    ignore
            end;
        true -> ignore
    end.

%%%===================================================================
%%% gen_server callbacks
%%%===================================================================
init([]) ->
    process_flag(trap_exit, true),
    {ok, []}.

handle_call(Req, From, State) ->
    case catch do_handle_call(Req, From, State) of
        {reply, Res, NewState} ->
            {reply, Res, NewState};
        Res ->
            ?ERR("Req Error:~p~n", [[Req, Res]]),
            {reply, ok, State}
    end.

handle_cast(Msg, State) ->
    case catch do_handle_cast(Msg, State) of
        {noreply, NewState} ->
            {noreply, NewState};
        Res ->
            ?ERR("Msg Error:~p~n", [[Msg, Res]]),
            {noreply, State}
    end.

handle_info(Info, State) ->
    case catch do_handle_info(Info, State) of
        {noreply, NewState} ->
            {noreply, NewState};
        Res ->
            ?ERR("Info Error:~p~n", [[Info, Res]]),
            {noreply, State}
    end.

terminate(_Reason, _State) ->
    ok.

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

%%%===================================================================
%%% Internal functions
%%%===================================================================
do_handle_call(_Req, _From, State)->
    {reply, ok, State}.

%% 发送防沉迷数据服务器
do_handle_cast({'upload_prevent_addiction_data', AccName, SerId, RoleId, RoleName, Pid, Type, Source}, State) ->
    [
        begin
            EncodeParams =
                case UrlId of
                    suyou   -> pack_req_suyou(AccName, SerId, RoleId, RoleName, Pid, Type, Source);
                    _       -> false
                end,
            case EncodeParams of
                false -> ignore;
                _ ->
                    case httpc:request(post,
                        {Url, [], "application/x-www-form-urlencoded", EncodeParams},
                        [{timeout, 3000}],
                        [{sync, false}]) of
                        {ok, RequestId} ->
                            put_request_info(RequestId, ?WAIT_REPONSE, RoleId);
                        {error, Reason} ->
                            ?ERR("do httpc request error: ~w", [Reason]),
                            error
                    end
            end
        end || {UrlId, Url} <- get_url_list()
    ],
    {noreply, State};

do_handle_cast(_Msg, State)->
    ?PRINT("Msg:~p~n", [_Msg]),
    {noreply, State}.

do_handle_info({http, ReplyInfo}, State) ->
    http_reply(ReplyInfo),
    {noreply, State};

do_handle_info(_Info, State)->
    ?PRINT("Info: ~p~n", [_Info]),
    {noreply, State}.

%% 处理http回应
%% {http,      ReplyInfo}, ReplyInfo:
%% {RequestId, saved_to_file}
%% {RequestId, {error, Reason}}
%% {RequestId, Result}
%% {RequestId, stream_start, Headers}
%% {RequestId, stream_start, Headers, HandlerPid}
%% {RequestId, stream, BinBodyPart}
%% {RequestId, stream_end, Headers}
http_reply({RequestId, saved_to_file}) ->
    erase_request_info(RequestId),
    ignore;
http_reply({RequestId, {error, _Reason}}) ->
    case erlang:get({prevent, RequestId}) of
        {RequestId, State, _Url, RoleId} ->
            ?ERR("request_prevent_addiction_error:~p~n", [[RoleId, State]]);
        _ ->
            skip
    end,
    erase_request_info(RequestId),
    ignore;
http_reply({RequestId, _}) ->
    erase_request_info(RequestId),
    ok;
http_reply({RequestId, _, _}) ->
    erase_request_info(RequestId),
    ignore;
http_reply({RequestId, _, _, _}) ->
    erase_request_info(RequestId),
    ignore;
http_reply(_) ->
    ignore.

pack_req_suyou(AccName, SerId, RoleId, RoleName, Pid, Type, BitSource) ->
    Time = utime:unixtime(),
    RoleData =
        [
            {<<"userId">>, util:make_sure_binary(AccName)},
            {<<"sid">>, SerId},
            {<<"roleId">>, util:make_sure_binary(integer_to_list(RoleId))},
            {<<"roleName">>, util:make_sure_binary(RoleName)},
            {<<"sessionId">>, util:make_sure_binary(pid_to_list(Pid))},
            {<<"time">>, Time},
            {<<"type">>, Type}
        ],
    JsonRoleData = mochijson2:encode(RoleData),
    Data = unicode:characters_to_list(list_to_binary("[" ++ JsonRoleData ++ "]")),
    SecretKey = ?SECRET_KEY,
    Source = util:bitstring_to_term(BitSource),
    SignList = ["data=", Data, "source=",  Source, "time=", Time, SecretKey],
    SignStr = lists:concat(SignList),
    Sign  = util:md5(SignStr),
    lists:concat(["data=", Data, "&source=",  Source, "&time=", Time, "&sign=", Sign]).

%% 添加请求信息
put_request_info(RequestId, State, RoleId)->
    put({prevent, RequestId}, {RequestId, State, RoleId}).

%% 清空请求信息
erase_request_info(RequestId)->
    erase({prevent, RequestId}).


%% get_url_list() -> [ {UrlId :: atom(), Url :: string:string()} ].
get_url_list() ->
    case get(ver_issuer) of
        ?VER_ISSUER_ML ->
            [
                {suyou, ?MONITOR_URL_SUYOU}
            ];
        _ ->
            [
                {suyou, ?MONITOR_URL_SUYOU}
            ]
    end.


