%%-----------------------------------------------------------------------------
%% module  :       mod_vie_rank_center
%% @author  :      zmh
%% Created :       20201026
%% description:    封榜榜单管理
%%-----------------------------------------------------------------------------
-module(mod_vie_rank_center).

-include("errcode.hrl").
-include("common.hrl").
-include("server.hrl").
-include("figure.hrl").
-include("vie_rank.hrl").
-include("custom_act.hrl").
-include("guild.hrl").

-export ([init/1, handle_call/3, handle_cast/2, handle_info/2, code_change/3, terminate/2]).
-export ([
    start_link/0,
    get_vie_role_ranks/6,
    update_role_vie/4,
    recalc_zone/1,
    gm_account/1,
    zero_clock/0,
    handle_merge/3
]).

-compile(export_all).


%%榜单
get_vie_role_ranks(Node,ZoneID,RoleID,MScore,BaseType,SubType)->
    gen_server:cast(?MODULE,{get_vie_role_ranks,Node,ZoneID,RoleID,MScore,BaseType,SubType}).

%%更新榜单
update_role_vie(Node,ZoneID,SubType,VieRole)->
    gen_server:cast(?MODULE,{update_role_vie,Node,ZoneID,SubType,VieRole}).


recalc_zone(CBMap)->
    #{zone_map := ZoneMap} = CBMap,
    ZoneList = maps:to_list(ZoneMap),
    gen_server:cast(?MODULE,{recalc_zone,ZoneList}),
    ok.

handle_merge(ToServerId, ToServerNum, MergeServers)->
    gen_server:cast(?MODULE,{handle_merge, ToServerId, ToServerNum, MergeServers}),
    ok.

zero_clock()->
    gen_server:cast(?MODULE,{zero_clock}),
    ok.


gm_account(SubType)->
    case lib_custom_act_util:get_act_cfg_info(?CUSTOM_ACT_TYPE_VIE_RANK,SubType) of
        #custom_act_cfg{start_time=STime}->
            skip;
        _->
            STime = utime:unixtime()
    end,
    gen_server:cast(?MODULE,{account_rank,10,SubType,STime}).

%%手动关闭 数据清理
kf_notify_other_module(?CUSTOM_ACT_STATUS_MANUAL_CLOSE, ActInfo, _Stime, _Etime)->
    #act_info{key={_,SubType},stime=_STime}=ActInfo,
    gen_server:cast(?MODULE,{manual_pre_clean,SubType}),
    ok;
kf_notify_other_module(?CUSTOM_ACT_STATUS_CLOSE, ActInfo, _Stime, _Etime)->
    #act_info{key={_,SubType},stime=STime}=ActInfo,
    gen_server:cast(?MODULE,{account_rank,600,SubType,STime}),
    ok;
kf_notify_other_module(_ActStatus, _ActInfo, _Stime, _Etime)->
    ok.

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

init([]) ->
    VieRanks = lib_vie_rank:load_vie_ranks(),
    SvrZoneMap = czone:get_svr_zone_map(),
    ActMap0 = init_vie_rank_data(SvrZoneMap,VieRanks),
    ActMap  = init_calc_rank(ActMap0),
    {ok,#vie_rank_mgr{act_map=ActMap}}.

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) ->
    ok.

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


do_handle_cast({get_vie_role_ranks,Node,ZoneID,RoleID,TmpScore,BaseType,SubType},State)->
    #vie_rank_mgr{act_map=ActMap}=State,
    ZoneMap = maps:get(SubType,ActMap,#{}),
    RoleRanks0 = maps:get(ZoneID,ZoneMap,[]),
    RoleRanks  = pack_data(RoleRanks0,[],50),
    case lists:keyfind(RoleID,#vie_rank.id,RoleRanks0) of
        #vie_rank{rank=Rrank,score=RValue}->
            skip;
        _->
            Rrank=0,RValue=TmpScore
    end,
    {ok,Bin} = pt_331:write(33169,[BaseType,SubType,Rrank,RValue,RoleRanks]),
    lib_server_send:send_to_uid(Node,RoleID,Bin),
    {noreply,State};


%%榜单更新
do_handle_cast({update_role_vie,Node,ZoneID,SubType,VieRole},State)->
    #vie_rank_mgr{act_map=ActMap}=State,
    #vie_rank{id=RoleID}=VieRole,
    ZoneMap = maps:get(SubType,ActMap,#{}),
    RoleRanks0 = maps:get(ZoneID,ZoneMap,[]),
    RoleRanks1 = lists:keystore(RoleID,#vie_rank.id,RoleRanks0,VieRole),
    RoleRanks2 = compare_vie(RoleRanks1),
    RankType   = lib_vie_rank:get_rank_type(SubType),
    RankMax    = lib_vie_rank:get_max_rank(SubType),
    NRoleRanks = compare_rank(RankType,RoleRanks2,1,RankMax,[]),
    NZoneMap   = maps:put(ZoneID,NRoleRanks,ZoneMap),
    NActMap = maps:put(SubType,NZoneMap,ActMap),
    NState = State#vie_rank_mgr{act_map=NActMap},
    brocast_ranks(Node,SubType,RoleID,NRoleRanks),
    save_vie_rank(SubType,VieRole),
    {noreply,NState};


%% 合服处理
do_handle_cast({handle_merge, ToServerId, ToServerNum, ServerIds}, State) ->
    ?INFO("~w:handle_merge:~w", [?MODULE, {ToServerId, ServerIds}]),
    NewState = handle_merge(State, ToServerId, ToServerNum, ServerIds),
    {noreply, NewState};

%% 更新ServerId对应的ZoneId的索引数据
%% Todo 分区变化 需要矫正数据
do_handle_cast({recalc_zone,ZoneList},State)->
    ?INFO("~w:handle_rezone:~w", [?MODULE, ?LINE]),
    NewState = do_recalc_zone(ZoneList,State),
    {noreply, NewState};

%% 结算排行榜
do_handle_cast({account_rank, Delay, SubType, STime}, State) ->
    erlang:send_after(Delay*1000,self(),{do_account_rank,STime,SubType}),
    {noreply,State};

do_handle_cast({zero_clock},State)->
    #vie_rank_mgr{act_map=ActMap}=State,
    Now = utime:unixtime(),
    Sql = io_lib:format(?SQL_VIE_RANK_BY_DTIME,[Now]),
    db:execute(Sql),
    ActMap0  = clean_over_dtime_data(Now,ActMap),
    NActMap  = init_calc_rank(ActMap0),
    {noreply,State#vie_rank_mgr{act_map=NActMap}};

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


do_handle_info({do_account_rank,STime,SubType},State)->
    NState = do_account_rank(State, STime, SubType),
    {noreply,NState};

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


pack_data([],Datas,_)->
    Datas;
pack_data([VieRank|T],Datas,Len)->
    #vie_rank{
        id=ID,
        name=Name,
        vip=Vip,
        svip=SVip,
        server_num=SNum,
        score=Score,rank=Rank
    }=VieRank,
    case Rank=<Len of
        true->
            pack_data(T,[{ID,Name,Vip,SVip,SNum,Rank,Score}|Datas],Len);
        _->
            pack_data(T,Datas,Len)
    end.

%%value降序
compare_vie(RoleRanks)->
    lists:sort(fun
        (A1, A2) ->
            compare_vie(A1, A2)
    end, RoleRanks).
compare_vie(A,B)->
    #vie_rank{rtime=RTimeA,score=ScoreA}=A,
    #vie_rank{rtime=RTimeB,score=ScoreB}=B,
    case ScoreA == ScoreB of
        true->
            RTimeA=<RTimeB;
        _->
            ScoreA>ScoreB
    end.

%%排名赋值
compare_rank(_RankType,[],_,_RankMax,SubRanks)->
    SubRanks;
compare_rank(RankType,[SubRank|SubRanks],Rank,RankMax,NSubRanks)->
    case Rank>RankMax of
        true->
            NSubRanks;
        _->
            #vie_rank{score=Score}=SubRank,
            NRank = calc_rank(RankType,Score,Rank),
            compare_rank(RankType,SubRanks,NRank+1,RankMax,[SubRank#vie_rank{rank=NRank}|NSubRanks])
    end.

%%计算排名
calc_rank(RankType,Score,Rank)->
    Limit = data_vie_rank:get_vie_req(RankType,Rank),
    case Score>=Limit of
        true->
            Rank;
        _->
            calc_rank(RankType,Score,Rank+1)
    end.

%%榜单广播
brocast_ranks(Node,SubType,RoleID,RoleRanks)->
    case lists:keyfind(RoleID,#vie_rank.id,RoleRanks) of
        #vie_rank{rank=Rrank,score=RScore}->
            skip;
        _->
            Rrank=0,RScore=0
    end,
    ShowRoleRanks  = pack_data(RoleRanks,[],50),
    {ok,Bin} = pt_331:write(33169,[?CUSTOM_ACT_TYPE_VIE_RANK,SubType,Rrank,RScore,ShowRoleRanks]),
    case Rrank=<50 of
        true->%%50名以内变化 通知利益相关人
            brocast_role_ranks(SubType,RoleRanks,ShowRoleRanks);
        _->%%只告诉自己
            lib_server_send:send_to_uid(Node,RoleID,Bin)
    end.

brocast_role_ranks(_,[],_)->
    ok;
brocast_role_ranks(SubType,[H|T],ShowRoleRanks)->
    #vie_rank{id=RoleID,rank=Rank,score=Score}=H,
    case Rank=<50 of
        true->
            {ok,Bin} = pt_331:write(33169,[?CUSTOM_ACT_TYPE_VIE_RANK,SubType,Rank,Score,ShowRoleRanks]),
            ServId = mod_player_create:get_serid_by_id(RoleID),
            clusters_center:apply_cast(ServId, lib_server_send, send_to_uid, [RoleID,Bin]);
        _->
            skip
    end,
    brocast_role_ranks(SubType,T,ShowRoleRanks).

%%榜单数据整理
init_vie_rank_data(SvrZoneMap,VieRanks)->
    init_vie_rank_data(SvrZoneMap,VieRanks,#{}).

init_vie_rank_data(_SvrZoneMap,[],ActMap)->
    ActMap;
init_vie_rank_data(SvrZoneMap,[H|T],ActMap)->
    #vie_rank{id=Rid,act=Act,server_id=ServId}=H,
    ZoneMap = maps:get(Act,ActMap,#{}),
    ZoneID = maps:get(ServId,SvrZoneMap,0),
    Ranks  = maps:get(ZoneID,ZoneMap,[]),
    NRanks = lists:keystore(Rid,#vie_rank.id,Ranks,H),
    NZoneMap = maps:put(ZoneID,NRanks,ZoneMap),
    NActMap = maps:put(Act,NZoneMap,ActMap),
    init_vie_rank_data(SvrZoneMap,T,NActMap).


%%初始计算排名
init_calc_rank(ActMap)->
    NActMap = maps:fold(
        fun(SubType, ZoneMap, Map) ->
            NZoneMap = init_calc_zone_rank(SubType,ZoneMap),
            maps:put(SubType, NZoneMap, Map)
        end,
    ActMap, ActMap),
    NActMap.

init_calc_zone_rank(SubType,ZoneMap)->
    RankType   = lib_vie_rank:get_rank_type(SubType),
    RankMax    = lib_vie_rank:get_max_rank(SubType),
    NZoneMap = maps:fold(
        fun(Zone, Ranks0, Map) ->
            Ranks1 = compare_vie(Ranks0),
            NRanks = compare_rank(RankType,Ranks1,1,RankMax,[]),
            maps:put(Zone, NRanks, Map)
        end,
    ZoneMap, ZoneMap),
    NZoneMap.

%%超时失效数据
clean_over_dtime_data(Now,ActMap)->
    NActMap = maps:fold(
        fun(SubType, ZoneMap, Map) ->
            NZoneMap = clean_zone_over_dtime_data(SubType,Now,ZoneMap),
            maps:put(SubType, NZoneMap, Map)
        end,
    ActMap, ActMap),
    NActMap.

clean_zone_over_dtime_data(SubType,Now,ZoneMap)->
    RankType   = lib_vie_rank:get_rank_type(SubType),
    RankMax    = lib_vie_rank:get_max_rank(SubType),
    NZoneMap = maps:fold(
        fun(Zone, Ranks0, Map) ->
            {IsDone, Ranks1} = do_clean_data(Now,Ranks0,[],false),
            case IsDone of
                true->
                    Ranks2 = compare_vie(Ranks1),
                    NRanks = compare_rank(RankType,Ranks2,1,RankMax,[]);
                _->
                    NRanks = Ranks0
            end,
            maps:put(Zone, NRanks, Map)
        end,
    ZoneMap, ZoneMap),
    NZoneMap.

do_clean_data(_Now,[],Ranks,IsDone)->
    {Ranks,IsDone};
do_clean_data(Now,[H|T],Ranks,IsDone)->
    case H#vie_rank.dtime<Now of
        true->
            do_clean_data(Now,T,Ranks,true);
        _->
            do_clean_data(Now,T,[H|Ranks],IsDone)
    end.

%% ---------------------------------------------------------------------------
%% @doc 合服处理
handle_merge(State, ToServerId, ToServerNum, ServerIds) ->
    SvrZoneMap = czone:get_svr_zone_map(),
    case maps:get(ToServerId, SvrZoneMap, false) of
        ToZoneId when is_integer(ToZoneId)->
            handle_merge(State, SvrZoneMap, ToServerId, ToServerNum, ToZoneId, ServerIds);
        _ ->
            State
    end.

handle_merge(State, _SvrZoneMap, _ToServerId, _ToServerNum, _ToZoneId, []) ->
    State;
handle_merge(State, SvrZoneMap, ToServerId, ToServerNum, ToZoneId, [FromServerId | T]) ->
    #vie_rank_mgr{act_map=ActMap}=State,
    NewState =  case maps:get(FromServerId, SvrZoneMap, false) of
        FromZoneId when is_integer(FromZoneId),FromZoneId =/= ToZoneId -> %% 游戏服合到其他分区了
            NActMap = maps:fold(
                fun(SubType, ZoneMap, Map) ->
                    NZoneMap = act_rank_handle_merge(SubType,ToServerId, ToServerNum, ToZoneId, FromServerId, FromZoneId, ZoneMap),
                    maps:put(SubType, NZoneMap, Map)
                end,
            ActMap, ActMap),
            State#vie_rank_mgr{act_map = NActMap};
        _ ->
            State
    end,
    handle_merge(NewState, SvrZoneMap, ToServerId, ToServerNum, ToZoneId, T).


%% 某个活动各个分区的排行榜
act_rank_handle_merge(SubType,ToServerId, ToServerNum, ToZoneId, FromServerId, FromZoneId, ZoneMap) ->
    FRanks = maps:get(FromZoneId,ZoneMap,[]),
    {RankRoles0, OtherRankRoles} = split_roles(FromServerId, ToServerId, ToServerNum, FRanks, [], []),
    RankRoles1 = compare_vie(RankRoles0),
    RankType   = lib_vie_rank:get_rank_type(SubType),
    RankMax    = lib_vie_rank:get_max_rank(SubType),
    NRoleRanks = compare_rank(RankType,RankRoles1,1,RankMax,[]),

    NZoneMap0  = maps:put(FromZoneId,NRoleRanks,ZoneMap),


    NZoneMap = case OtherRankRoles of
        [] -> %% 没有玩家需要移动到其他分区
            NZoneMap0;
        _ -> %% 需要移动到其他分区的玩家重新上榜
            save_rank_roles(OtherRankRoles),
            roles_hit_rank(OtherRankRoles, NZoneMap0, SubType, ToZoneId)
    end,
    NZoneMap.


%% 排行榜里面server_id服的玩家和其他服的玩家分开
split_roles(_ServerId, _ToServerId, _ToServerNum, [], RankRoles, OtherRankRoles) ->
    {RankRoles, OtherRankRoles};
split_roles(ServerId, ToServerId, ToServerNum, [Role | T], RankRoles, OtherRankRoles) ->
    {RankRoles2, OtherRankRoles2} = case Role of
        #vie_rank{server_id = ServerId} -> %% 是被合服的玩家
            Role2 = Role#vie_rank{server_id = ToServerId,server_num = ToServerNum},
            {RankRoles, [Role2 | OtherRankRoles]};
        _ ->
            {[Role | RankRoles], OtherRankRoles}
    end,
    split_roles(ServerId, ToServerId, ToServerNum, T, RankRoles2, OtherRankRoles2).


%% 需要移动到其他分区的玩家重新上榜
roles_hit_rank(OtherRankRoles, ZoneMap, SubType, ToZoneId) ->
    TRanks = maps:get(ToZoneId,ZoneMap,[]),
    NTRanks0 = TRanks++OtherRankRoles,
    NTRanks1 = compare_vie(NTRanks0),
    RankType   = lib_vie_rank:get_rank_type(SubType),
    RankMax    = lib_vie_rank:get_max_rank(SubType),
    NTRanks = compare_rank(RankType,NTRanks1,1,RankMax,[]),
    %save_rank_roles(NTRanks),

    DelRoles = [
        Role || Role = #vie_rank{id = Id} <- OtherRankRoles
        ,lists:keymember(Id, #vie_rank.id, NTRanks) =:= false
    ],
    DelRoles2 = [
        Role || Role = #vie_rank{id = Id} <- TRanks
        ,lists:keymember(Id, #vie_rank.id, NTRanks) =:= false
    ],

    batch_del_rank_role(SubType, DelRoles ++ DelRoles2),

    maps:put(ToZoneId,NTRanks,ZoneMap).


%% @doc 批量保存排行榜上的玩家。
save_rank_roles(RankRoles) ->
    DbRoleList = format_save_rank_roles([], RankRoles),
    batch_save(DbRoleList),
    ok.

batch_save([]) ->
    ok;
batch_save(DbRoleList) ->
    ArgsString = string:join(DbRoleList, ","),
    Sql = io_lib:format(?SQL_VIE_RANK_BATCH, [ArgsString]),
    db:execute(Sql),
    ok.

format_save_rank_roles(DbRoleList, []) ->
    DbRoleList;
format_save_rank_roles(DbRoleList, [Role | T]) ->
    DbRole = format_save_rank_role(Role),
    DbRoleList2 = [DbRole | DbRoleList],
    format_save_rank_roles(DbRoleList2, T).

format_save_rank_role(RankRole)->
    #vie_rank{
        id = Rid,
        name = RName,
        server_num = ServNum,
        server_id = ServId,
        act = SubType,
        vip = Vip,
        svip = SVip,
        score = Score,
        rtime = RTime,
        dtime = DTime
    } = RankRole,
    Data = [
        SubType, Rid, RName, ServId, ServNum, Vip, SVip,Score, RTime,DTime
    ],
    io_lib:format("(~p,~p,'~ts',~p,~p,~p,~p,~p,~p,~p)", Data).



%% @doc 批量删除排行榜上的角色数据
batch_del_rank_role(_ActId, []) ->
    ok;
batch_del_rank_role(ActId, RankRoles) ->
    RoleIdList = [
        erlang:integer_to_list(Id) || #vie_rank{id = Id} <- RankRoles
    ],
    RoleIdsStr = string:join(RoleIdList, ","),
    Sql = io_lib:format(?SQL_VIE_RANK_BATCH_DEL, [ActId, RoleIdsStr]),
    db:execute(Sql),
    ok.


%$%重新分区处理
do_recalc_zone([],State)->
    State;
do_recalc_zone([{OZone, NZone}|T],State)->
    NState = handle_rezone(State,NZone,OZone),
    do_recalc_zone(T,NState).

%% @doc 重新分区处理
handle_rezone(State, NZone, OZone) ->
    #vie_rank_mgr{act_map = ActMap} = State,
    NActMap = maps:fold(
        fun(SubType, ZoneMap, Map) ->
            NZoneMap = act_rank_handle_rezone(SubType, NZone, OZone, ZoneMap),
            maps:put(SubType, NZoneMap, Map)
        end,
    ActMap, ActMap),
    State#vie_rank_mgr{act_map = NActMap}.

%% 某个活动各个分区的排行榜
act_rank_handle_rezone(SubType,NZone, OZone, ZoneMap) ->
    OtherRankRoles = maps:get(OZone,ZoneMap,[]),
    ZoneMap0 = maps:remove(OZone,ZoneMap),
    NZoneMap = case OtherRankRoles of
        [] -> %% 没有玩家需要移动到其他分区
            ZoneMap0;
        _ -> %% 需要移动到其他分区的玩家重新上榜
            roles_hit_rank(OtherRankRoles, ZoneMap0, SubType, NZone)
    end,
    NZoneMap.

%% @doc 结算排行榜
do_account_rank(State,STime, SubType) ->
    #vie_rank_mgr{act_map = ActMap} = State,
    ZoneMap = maps:get(SubType,ActMap,#{}),
    %broadcast_act_rank(ZoneMap),
    %% 1.> 先写日志保存排行榜数据
    ZoneRanks = maps:to_list(ZoneMap),
    log_center_vie_rank(SubType,ZoneRanks),
    %% 2.> 发奖励
    settlement_rank_award(SubType,STime,ZoneRanks),
    State.

%% 结算排行榜，发奖励。
settlement_rank_award(SubType,STime,ZoneRanks) ->
    [settlement_rank_award_do(Zone,SubType,STime,Ranks) || {Zone,Ranks} <- ZoneRanks],
    ok.

settlement_rank_award_do(ZoneId,SubType,STime,VieRanks) ->
    ServerRList = classify_roles_by_server_id(VieRanks, []),
    [
        clusters_center:apply_cast(
            ServerId, {?MODULE, race_rank_award, [ZoneId,SubType,STime,RoleList]}
        ) || {ServerId, RoleList} <- ServerRList
    ],
    ok.

classify_roles_by_server_id([], ServerList) ->
    ServerList;
classify_roles_by_server_id([RankRole | T], ServerList) ->
    #vie_rank{server_id = ServerId} = RankRole,
    ServerList2 = case lists:keytake(ServerId, 1, ServerList) of
        {value, {ServerId, RoleList}, LessServerList} ->
            RoleList2 = [RankRole | RoleList],
            [{ServerId, RoleList2} | LessServerList];
        false ->
            [{ServerId, [RankRole]} | ServerList]
    end,
    classify_roles_by_server_id(T, ServerList2).


%% @doc 结算排行榜，发奖励.
race_rank_award(ZoneId,SubType,STime,RankRoles)->
    OpDay  = max(util:get_open_day(STime),1),
    race_rank_award(ZoneId,SubType,STime,OpDay,RankRoles).

race_rank_award(_ZoneId,_SubType,_STime,_OpDay,[]) ->
    ok;
race_rank_award(ZoneId,SubType,STime,OpDay,[RankRole|T]) ->
    #vie_rank{
        id = RoleId,
        rank = Rank,
        score = Score
    } = RankRole,
    Awards = calc_rank_awards(?CUSTOM_ACT_TYPE_VIE_RANK,SubType,OpDay,Rank),
    case Awards /= [] of
        true->
            #custom_act_cfg{name=ActName} = lib_custom_act_util:get_act_cfg_info(?CUSTOM_ACT_TYPE_VIE_RANK,SubType),
            Title = utext:get(33179001),
            Content = utext:get(33179002, [ActName, Score, Rank]),
            lib_mail_api:send_sys_mail([RoleId], Title, Content, Awards),
            %% local log
            local_log_award(ZoneId,SubType,RankRole);
        _->
            String = "vie_rank_award no config:RoleId:~w,ActId:~w,Ranking:~w,OpDay:~w",
            ?ERR(String, [RoleId, SubType, Rank,OpDay])
    end,
    race_rank_award(ZoneId,SubType,STime,OpDay,T).


calc_rank_awards(Type,SubType,OpDay,Rank)->
    Grades = lib_custom_act_util:get_act_reward_grade_list(Type,SubType),
    calc_rank_awards(Grades,Type,SubType,OpDay,Rank).
calc_rank_awards([],_Type,_SubType,_OpDay,_Rank)->
    [];
calc_rank_awards([H|T],Type,SubType,OpDay,Rank)->
    case lib_custom_act_util:get_act_reward_cfg_info(Type,SubType,H) of
        #custom_act_reward_cfg{condition=Cons,reward=Awards}->
            case lists:keyfind(rank_seq,1,Cons) of
                {_,[Min,Max]} when Min=<Rank,Rank=<Max ->
                    case lists:keyfind(day_range,1,Cons) of
                         {_,[MinD,MaxD]} when MinD=<OpDay,OpDay=<MaxD->
                            Awards;
                        _->
                            calc_rank_awards(T,Type,SubType,OpDay,Rank)
                    end;
                _->
                    calc_rank_awards(T,Type,SubType,OpDay,Rank)
            end;
        _->
            calc_rank_awards(T,Type,SubType,OpDay,Rank)
    end.


%%本地结算日志
local_log_award(ZoneId,SubType,RankRole) ->
    #vie_rank{
        id = RoleId,name = Name,
        server_id = ServerId,server_num = ServerNum,
        score = Score, rank = Rank, rtime = RTime, dtime=DTime
    } = RankRole,
    Data = [
        SubType, ZoneId, RoleId, Name, ServerId, ServerNum
        ,Score, Rank, RTime, DTime, utime:unixtime()
    ],
    lib_log_api:log_local_vie_rank(Data),
    ok.


%% @doc 跨服排行榜数据日志。
log_center_vie_rank(SubType,ZoneRanks) ->
    Now = utime:unixtime(),
    [log_vie_rank_do(Zone,SubType,Now,Ranks)||{Zone,Ranks}<-ZoneRanks].

log_vie_rank_do(_Zone,_SubType,_Now,[]) ->
    ok;
log_vie_rank_do(Zone,SubType,Now,RoleList) ->
    DbRoleList2 = format_log_rank_roles([], Zone,SubType, Now, RoleList),
    batch_log(DbRoleList2).

batch_log([]) ->
    ok;
batch_log(DbRoleList) ->
    ArgsString = string:join(DbRoleList, ","),
    Sql = io_lib:format(?SQL_LOG_RANK_BATCH, [ArgsString]),
    db:execute(Sql),
    ok.

format_log_rank_roles(DbRoleList, _Zone,_SubType,_Now, []) ->
    DbRoleList;
format_log_rank_roles(DbRoleList, Zone,SubType, Now, [Role | T]) ->
    DbRole = format_log_rank_role(Role,Zone,SubType, Now),
    DbRoleList2 = [DbRole | DbRoleList],
    format_log_rank_roles(DbRoleList2,Zone,SubType, Now, T).

format_log_rank_role(RankRole, Zone,SubType, Now)->
    #vie_rank{
        id = RoleId,name = Name, server_id = ServerId
        ,server_num = ServerNum, score = Score, rank = Rank, rtime = RTime,dtime=DTime
    } = RankRole,
    Data = [
        SubType, Zone, RoleId, Name, ServerId, ServerNum
        ,Score, Rank, RTime, DTime, Now
    ],
    io_lib:format("(~p,~p,~p,'~ts',~p,~p,~p,~p,~p,~p,~p)", Data).


%%单个数据更新保存
save_vie_rank(SubType,VieRole)->
    #vie_rank{
        id = RoleId,name = Name, server_id = ServerId,vip = Vip,svip = SVip,
        server_num = ServerNum, score = Score, rtime = RTime,dtime=DTime
    } = VieRole,
    Data = [
        SubType, RoleId, Name, ServerId, ServerNum
        ,Vip,SVip,Score, RTime, DTime
    ],
    Sql = io_lib:format(?SQL_VIE_RANK_INS,Data),
    db:execute(Sql).


ask_reward_status(Player, Type, SubType)->
    ActInfo = #act_info{key = {Type, SubType}},
    lib_custom_act_do_normal:send_reward_status(Player, ActInfo).