%%% ----------------------------------------------------
%%% @Module:        mod_3v3_rank
%%% @Author:        zhl
%%% @Description:   跨服3v3排行榜
%%% @Created:       2017/07/07
%%% ----------------------------------------------------

-module(mod_3v3_rank).
-behaviour(gen_server).

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

-export([
        start_link/0,                           %% 启动3v3排行榜
        replace_3v3_rank/0,                     %% 更新3v3排行榜数据
        refresh_3v3_rank/1,                     %% 刷新排行榜
        get_page_rank/1,                        %% 获取荣誉排行榜
        get_score_rank/0,
        get_score_rank/1,                       %% 获取天梯排行榜

        % after_merge_fix/1,                      %% 合服校正
        get_my_tier/2,
        gm_empty_3v3_rank/0,                    %% 秘籍结算排行榜

        test/0
    ]).

-include("common.hrl").
-include("3v3.hrl").

-define(RANK_REFRESH_TIME, 0).

%% 刷新排行榜
refresh_3v3_rank(Args) ->
    gen_server:cast(?MODULE, {refresh_3v3_rank, Args}).

%% 获取荣誉排行榜
get_page_rank(Args) ->
    gen_server:cast(?MODULE, {get_page_rank, Args}).

%% 获取荣誉排行榜
gm_empty_3v3_rank() ->
    gen_server:cast(?MODULE, {gm_empty_3v3_rank}).

%% 获取天梯排行榜
get_score_rank() ->
    ?MODULE ! {get_score_rank}.

get_score_rank(Args) ->
    gen_server:cast(?MODULE, {get_score_rank, Args}).

%% 更新3v3排行榜数据 - 每次活动结束写入一次
replace_3v3_rank() ->
    ?MODULE ! {replace_3v3_rank}.

% %% 合服校正
% after_merge_fix(Args) ->
%     gen_server:cast(?MODULE, {after_merge_fix, Args}).

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

%% 启动3v3排行榜
start_link() ->
    gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).

test() -> ok.

init([]) ->
    process_flag(trap_exit, true),
    ets:new(?ETS_RANK_DATA, [named_table, {keypos, #kf_3v3_rank_data.role_id}, {read_concurrency, true}]),
    %% 每周六清空一次排行榜
    % NowSec = utime:get_seconds_from_midnight(),
    % erlang:send_after((86400 - NowSec) * 1000, self(), {empty_3v3_rank}),
    LeftTime = utime:tomorrow() - utime:unixtime(),
    erlang:send_after(LeftTime * 1000, self(), {empty_3v3_rank}),
    RankData = lib_3v3_rank:load_3v3_rank(),
    case RankData of
        [] -> skip;
        _ -> ets:insert(?ETS_RANK_DATA, RankData)
    end,
    {ok, {}}.

handle_call(_Request, _From, State) ->
    {reply, ok, State}.

handle_cast(Request, State) ->
    try
        do_handle_cast(Request, State)
    catch
        throw:{error, _Reason} ->
            {noreply, State};
        throw:_ ->
            {noreply, State};
        _:Error ->
            ?ERR("handle call exception~n"
                 "error:~p~n"
                 "state:~p~n"
                 "stack:~p", [Error, State, erlang:get_stacktrace()]),
            {noreply, State}
    end.

handle_info(Request, State) ->
    try
        do_handle_info(Request, State)
    catch
        throw:{error, _Reason} ->
            {noreply, State};
        throw:_ ->
            {noreply, State};
        _:Error ->
            ?ERR("handle call exception~n"
                 "error:~p~n"
                 "state:~p~n"
                 "stack:~p", [Error, State, erlang:get_stacktrace()]),
            {noreply, State}
    end.

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

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

%% 刷新排行榜
do_handle_cast({refresh_3v3_rank, [#kf_3v3_rank_data{} | _] = Args}, State) ->
    NowTime = utime:unixtime(),
    LastRefreshTime
    = case get(rank_3v3_last_refresh_time) of
          undefined ->
              put(rank_3v3_last_refresh_time, NowTime),
              NowTime;
          Time ->
              Time
      end,
    {ok, KeyValueList} = lib_3v3_rank:refresh_3v3_rank(Args, []),
    update_to_ets(KeyValueList),
    if
        NowTime - LastRefreshTime > ?RANK_REFRESH_TIME ->
            do_handle_info({get_score_rank}, State);
        true ->
            {noreply, State}
    end ;
do_handle_cast({refresh_3v3_rank, Args}, State) ->
    {ok, KeyValueList} = lib_3v3_rank:refresh_3v3_rank(Args),
    update_to_ets(KeyValueList),
    {noreply, State};

%% 获取荣誉排行榜
do_handle_cast({get_page_rank, [Page, ServerId, RoleID]}, State) ->
    % case ets:match_object(?ETS_RANK_DATA, #kf_3v3_rank_data{platform = Platform,
    %   server_num = ServerNum, role_id = RoleID, _ = '_'})
    % of
    %   [#kf_3v3_rank_data{role_id = RoleID}] -> ok;
    %   _ -> RoleID = false
    % end,
    {NewPage, RankID, RankList} = lib_3v3_rank:get_page_rank([Page, RoleID]),
    clusters_center:apply_cast(ServerId, lib_3v3_local, send_page_rank, [[RoleID, NewPage, RankID, RankList]]),
    {noreply, State};

do_handle_cast({get_my_tier, Node, RoleId}, State) ->
    case ets:select(?ETS_RANK_DATA, [{#kf_3v3_rank_data{role_id=RoleId,_='_',tier ='$1', star ='$2'}, [], ['$$']}]) of
        [[Tier, Star]] ->
            clusters_center:apply_cast(Node, lib_3v3_local, get_tier_respond, [RoleId, Tier, Star]);
        _ ->
            skip
    end,
    {noreply, State};

%% 获取天梯排行榜
do_handle_cast({get_score_rank, [ServerId, RoleSid]}, State) ->
    ScoreRank = lib_3v3_rank:get_score_rank(),
    clusters_center:apply_cast(ServerId, mod_3v3_local, send_score_rank, [{RoleSid, ScoreRank}]),
    {noreply, State};

% %% 合服校正
% do_handle_cast({after_merge_fix, Args}, State) ->
%     RankData = lib_3v3_rank:after_merge_fix(Args),
%     ets:insert(?ETS_RANK_DATA, RankData),
%     {noreply, State};


do_handle_cast({gm_empty_3v3_rank}, State) ->
%%    DayOfWeek = utime:day_of_week(utime:unixtime() - 100), %% 确保时间是零点前
    lib_3v3_rank:empty_3v3_rank(), %% 发送奖励并清空周榜
    ScoreRank = [],
    clusters_center:apply_to_all_node(mod_3v3_local, send_score_rank, [{ScoreRank}]),
    ets:delete_all_objects(?ETS_RANK_DATA),
    {noreply, State};

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

%% 更新3v3排行榜数据
do_handle_info({replace_3v3_rank}, State) ->
    NowSec = utime:get_seconds_from_midnight(),
    case lib_3v3_center:load_act_time() of
        {_, EdTime} -> %% 每次活动结束写入数据一次
            erlang:send_after((EdTime - NowSec) * 1000, self(), {replace_3v3_rank});
        _ -> skip
    end,
    lib_3v3_rank:replace_3v3_rank(),
    erlang:send_after(200000, self(), {get_score_rank}), %% 活动后3分钟推送天梯排行榜
    {noreply, State};

do_handle_info({get_score_rank}, State) ->
    ScoreRank = lib_3v3_rank:get_score_rank(),
    clusters_center:apply_to_all_node(mod_3v3_local, send_score_rank, [{ScoreRank}]),
    put(rank_3v3_last_refresh_time, utime:unixtime()),
    {noreply, State};

%% 每月清空一次数据库
do_handle_info({empty_3v3_rank}, State) ->
    NowTime = utime:unixtime(),
%%    DayOfWeek = utime:day_of_week(utime:unixtime() - 100), %% 确保时间是零点
    D = utime:day_of_month(NowTime + 100),
    % erlang:send_after(86400 * 1000, self(), {empty_3v3_rank}), %% 每周六清空一次排行榜
    erlang:send_after((utime:tomorrow() - NowTime) * 1000, self(), {empty_3v3_rank}),
    if
        D == 1 -> %% 每月1号结算
            lib_3v3_rank:empty_3v3_rank(), %% 发送奖励并清空周榜
            ScoreRank = [],
            clusters_center:apply_to_all_node(mod_3v3_local, send_score_rank, [{ScoreRank}]),
            ets:delete_all_objects(?ETS_RANK_DATA);
        true -> skip
    end,
    {noreply, State};


% do_handle_info({test}, State) ->
%     % RankList = ets:tab2list(?ETS_RANK_DATA),
%     % io:format("-----{test}-----~p~n", [RankList]),
%     RankData = lib_3v3_rank:merge_test(),
%     lib_3v3_rank:replace_3v3_rank(RankData),
%     {noreply, State};

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

%% 更新ets
%% @desc : 注意，这个方法只有mod_3v3_local这个进程才能使用
update_to_ets(KeyValueList) ->
    F = fun({Type, Tab, Obejct}) ->
        case Type of
            update -> ets:insert(Tab, Obejct);
            delete -> ets:delete_object(Tab, Obejct);
            _ -> skip
        end
    end,
    lists:foreach(F, KeyValueList).
