%%%------------------------------------
%%% @Module  : common_rank_logic
%%% @Author  :  xiaoxiang
%%% @Created :  2016-11-17
%%% @Description: 通用榜单
%%%------------------------------------

-module(common_rank_logic).


-export([
    init/0
    ,get_rank_list_by_rank_type/1
    ,sort_rank_list/1
    , refresh_common_rank/3
    , interval_refresh_dsgt_rank/1
    , timer_refresh_common_rank_logic/2
    , send_rank_list/7
    , get_top_rank/5
    , get_first_top_info/4
    , get_top_rank_list/3
    , local_rank_upload/2
    , send_top_rank_info/1
]).

-export([
    gm_reset_first_top/2
    ,role_reset_first_top/1
    ,role_ta_rank_ret_1/3
    ]).

-compile(export_all).

-include("errcode.hrl").
-include("common_rank.hrl").
-include("common.hrl").
-include("server_kv.hrl").
-include("relationship.hrl").
-include("figure.hrl").
-include("role.hrl").
-include("def_module.hrl").
-include("def_fun.hrl").
-include("language.hrl").
-include("goods.hrl").
-include("predefine.hrl").
-include("server.hrl").
-include("rec_offline.hrl").
-include("daily.hrl").
-include("guild_tribe.hrl").
-include("role_foster.hrl").
-include("guild.hrl").

make_record(common_rank_guild, [RankType, GuildId, GuildName_B, Flag, ChairmanId,
    ChairmanName_B, Lv, MembersNum, Value, SecondValue, ThirdValue, Time]) ->
    GuildName = util:make_sure_list(GuildName_B),
    ChairmanName = util:make_sure_list(ChairmanName_B),
    #common_rank_guild{
        guild_key     = {RankType, GuildId},
        rank_type     = RankType,
        guild_id      = GuildId,
        guild_name    = GuildName,
        flag          = Flag,
        chairman_id   = ChairmanId,
        chairman_name = ChairmanName,
        lv            = Lv,
        members_num   = MembersNum,
        value         = Value,
        second_value  = SecondValue,
        third_value   = ThirdValue,
        time          = Time
    };

make_record(common_rank_role, [RankType, RoleId, Value, SecondValue, ThirdValue, ExtraValue, Time, OffTime]) ->
    ExtraValue1 = if RankType == ?RANK_TYPE_BABY ->
            util:make_sure_list(ExtraValue);
        true ->
            util:bitstring_to_term(ExtraValue)
    end,
    #common_rank_role{
        role_key      = {RankType, RoleId},
        rank_type     = RankType,
        role_id       = RoleId,
        value         = Value,
        display_value = Value,
        second_value  = SecondValue,
        third_value   = ThirdValue,
        extra_value   = ExtraValue1,
        time          = Time,
        off_time      = OffTime
    }.

init() ->
    %% 个人榜单
    List = db_common_rank_role_select(),
    RoleList = [make_record(common_rank_role, T) || T <- List],
    RankMaps = get_standard_sort_rank_maps(common_rank_role, RoleList),
    RoleLimitList = clean_redundant_rank_data_from_db(RankMaps),
    %% 公会榜单
    List1 = db_common_rank_guild_select(),
    GuildList = [make_record(common_rank_guild, T) || T <- List1],
    GuildMaps = get_standard_sort_rank_maps(common_rank_guild, GuildList),
    GuildLimitList = clean_redundant_rank_data_from_db(GuildMaps),
    RankLimit = maps:from_list(lists:append(RoleLimitList, GuildLimitList)),
    %% 点赞
    List2 = db_common_rank_praise_select(),
    F2 = fun([Type, Id, PraiseNum]) -> {{Type, Id}, PraiseNum} end,
    PraiseList = lists:map(F2, List2),
    PraiseMaps = maps:from_list(PraiseList),
    %% 首度目标数据
    List3 = db_common_rank_first_top(),
    TopList = [{{Type, Target}, {RoleId, Time}} || [Type, Target, RoleId, Time] <- List3],
    TopMaps = maps:from_list(TopList),
    %% 第一公会id
    FirstGuildId =
    case util:get_merge_day() of
       1 -> 0; %% 合服的时候第一次 把所有公会称号清了再发
       _ -> %% 其他情况 次日还是这公会第一的话 不会清了再发
           case maps:get(?RANK_TYPE_GUILD, GuildMaps, []) of
               [] -> 0;
               GuildL ->
                   [No1CommonRankGuild | _] = GuildL,
                   No1CommonRankGuild#common_rank_guild.guild_id
           end
   end,
   insert_rank_list(RankMaps),
    State = #common_rank_state{
        guild_maps = GuildMaps,
        old_first_guild = FirstGuildId,
        rank_limit = RankLimit,
        praise_maps = PraiseMaps,
        first_top = TopMaps
    },
    {ok, NewState} = refresh_average_lv(State),
    NewState.

%% 获得标准排序Maps(被截取了长度) Key:RankType Value:[#common_rank_role{}]
get_standard_sort_rank_maps(common_rank_role, RoleList) ->
    MapsKeyList = get_sort_rank_maps(common_rank_role, RoleList),
    F = fun({RankType, RankList}) ->
        #rank_config{rank_max = MaxRankLen, rank_limit = Limit} = lib_common_rank:get_rank_config(RankType),
        NewRankList0 = lists:sublist(RankList, MaxRankLen),
        NewRankList = [RankRole || RankRole <- NewRankList0, RankRole#common_rank_role.value >= Limit],
        {RankType, NewRankList}
        end,
    NewKeyList = lists:map(F, MapsKeyList),
    NewMaps = maps:from_list(NewKeyList),
    NewMaps;

get_standard_sort_rank_maps(common_rank_guild, RoleList) ->
    MapsKeyList = get_sort_rank_maps(common_rank_guild, RoleList),
    F = fun({RankType, RankList}) ->
        #rank_config{rank_max = MaxRankLen} = lib_common_rank:get_rank_config(RankType),
        %% MaxRankLen = data_common_rank:get_config({max_rank_len, RankType}),
        NewRankList = lists:sublist(RankList, MaxRankLen),
        {RankType, NewRankList}
        end,
    NewKeyList = lists:map(F, MapsKeyList),
    NewMaps = maps:from_list(NewKeyList),
    NewMaps.

%% 分类到Maps,然后对Maps的Value排序 Key:RankType Value:[#common_rank_role{}]
get_sort_rank_maps(common_rank_role, RoleList) ->
    F = fun(#common_rank_role{rank_type = RankType} = RankRole, Maps) ->
        case maps:get(RankType, Maps, false) of
            false -> NewList = [RankRole];
            List -> NewList = [RankRole | List]
        end,
        maps:put(RankType, NewList, Maps)
        end,
    Maps = lists:foldl(F, maps:new(), RoleList),
    NewKeyList = sort_rank_maps(Maps),
    NewKeyList;

get_sort_rank_maps(common_rank_guild, GuildList) ->
    F = fun(#common_rank_guild{rank_type = RankType} = RankGuild, Maps) ->
        case maps:get(RankType, Maps, false) of
            false -> NewList = [RankGuild];
            List -> NewList = [RankGuild | List]
        end,
        maps:put(RankType, NewList, Maps)
        end,
    Maps = lists:foldl(F, maps:new(), GuildList),
    NewKeyList = sort_rank_maps(Maps),
    NewKeyList.

%% 对Maps的Value排序
sort_rank_maps(Maps) ->
    MapsKeyList = maps:to_list(Maps),
    F = fun({Key, List}) ->
        RankList = sort_rank_list(List),
        {Key, RankList}
        end,
    NewKeyList = lists:map(F, MapsKeyList),
    NewKeyList.

sort_rank_list(List) ->
    F = fun(A, B) ->
        if
            is_record(A, common_rank_role) ->
                if
                    A#common_rank_role.value > B#common_rank_role.value -> true;
                    A#common_rank_role.value == B#common_rank_role.value ->
                        SecRankTypeList = [?RANK_TYPE_DESIGNATION, ?RANK_TYPE_FASHION, ?RANK_TYPE_DRESS] ++ ?RANK_TYPE_FOSTER,
                        case lists:member(A#common_rank_role.rank_type, SecRankTypeList) of
                            true ->
                                if
                                    A#common_rank_role.second_value > B#common_rank_role.second_value -> true;
                                    A#common_rank_role.second_value == B#common_rank_role.second_value ->
                                        case lists:member(A#common_rank_role.rank_type, ?RANK_TYPE_FOSTER) of
                                            true ->
                                                A#common_rank_role.third_value >= B#common_rank_role.third_value;
                                            _ ->
                                                A#common_rank_role.time =< B#common_rank_role.time
                                        end;
                                    true ->
                                        false
                                end;
                            _ ->
                                A#common_rank_role.time =< B#common_rank_role.time
                        end;
                    true -> false
                end;
            is_record(A, common_rank_guild) ->
                if
                    A#common_rank_guild.value > B#common_rank_guild.value -> true;
                    A#common_rank_guild.value == B#common_rank_guild.value ->
                        A#common_rank_guild.time =< B#common_rank_guild.time;
                    true -> false
                end;
            true ->
                false
        end
        end,
    NewList = lists:sort(F, List),

    F1 = fun(Member, {TempList, Value}) ->
        if
            is_record(Member, common_rank_role) ->
                NewMember = Member#common_rank_role{rank = Value},
                NewTempList = [NewMember | TempList],
                {NewTempList, Value + 1};
            is_record(Member, common_rank_guild) ->
                NewMember = Member#common_rank_guild{rank = Value},
                NewTempList = [NewMember | TempList],
                {NewTempList, Value + 1};
            true ->
                {TempList, Value}
        end

         end,
    {TmpRankList, _} = lists:foldl(F1, {[], 1}, NewList),
    lists:reverse(TmpRankList).

%% 清理数据库的冗余数据,防止数据过多
clean_redundant_rank_data_from_db(RankMaps) ->
    MapsKeyList = maps:to_list(RankMaps),
    F = fun({RankType, []}) ->
        #rank_config{rank_limit = Limit} = lib_common_rank:get_rank_config(RankType),
        {RankType, Limit};
        ({RankType, RankList}) ->
            #rank_config{rank_limit = Limit, rank_max = RankMax} = lib_common_rank:get_rank_config(RankType),
            case length(RankList) >= RankMax of
                true ->
                    RankLast = lists:last(RankList),
                    case RankType of
                        ?RANK_TYPE_GUILD ->
                            #common_rank_guild{value = Value} = RankLast;
                        _ ->
                            #common_rank_role{value = Value} = RankLast
                    end,
                    db_common_rank_delete_by_value(RankType, Value),
                    {RankType, max(Value, Limit)};
                false ->
                    {RankType, Limit}
            end
        end,
    lists:map(F, MapsKeyList).

insert_rank_list(RankMaps) ->
    maps:map(fun(RankType, RankList) ->
        erlang:put(?RANK_TYPE_KEY(RankType), RankList)
    end, RankMaps).

insert_rank_list(RankType, RankList) ->
    erlang:put(?RANK_TYPE_KEY(RankType), RankList).

get_rank_list_by_rank_type(RankType) ->
    case erlang:get(?RANK_TYPE_KEY(RankType)) of
        RankList = [_|_] -> ok;
        _   -> RankList = []
    end,
    RankList.

%% @param [{RankType, CommonRankRole}]
refresh_common_rank_by_list(State, List) ->
    F = fun({RankType, CommonRank}, TmpState) ->
        {ok, NewTmpState} = refresh_common_rank(TmpState, RankType, CommonRank),
        NewTmpState
        end,
    NewState = lists:foldl(F, State, List),
    {ok, NewState}.

%% 解散公会
disband_guild(State, GuildId, RankTypeList) ->
    F = fun(RankType, TempState) ->
        {ok, NewTmpState} = disband_guild_help(TempState, RankType, GuildId),
        NewTmpState
        end,
    NewState = lists:foldl(F, State, RankTypeList),
    {ok, NewState}.

disband_guild_help(State, RankType, GuildId) ->
    #common_rank_state{guild_maps = GuildMaps} = State,
    RankList = maps:get(RankType, GuildMaps, []),
    case lists:keyfind({RankType, GuildId}, #common_rank_guild.guild_key, RankList) of
        #common_rank_guild{} ->
            NewRankList = lists:keydelete({RankType, GuildId}, #common_rank_guild.guild_key, RankList),
            db_common_rank_delete_by_id(RankType, GuildId),
            NewRankList2 = sort_rank_list(NewRankList);
        false ->
            NewRankList2 = RankList
    end,
    NewGuildMaps = maps:put(RankType, NewRankList2, GuildMaps),
    {ok, State#common_rank_state{guild_maps = NewGuildMaps}}.

rename_guild(State, GuildId, Name, RankTypeList) ->
    F = fun(RankType, TempState) ->
        {ok, NewTmpState} = rename_guild_help(TempState, RankType, GuildId, Name),
        NewTmpState
        end,
    NewState = lists:foldl(F, State, RankTypeList),
    {ok, NewState}.

rename_guild_help(State, RankType, GuildId, Name) ->
    #common_rank_state{guild_maps = GuildMaps} = State,
    RankList = maps:get(RankType, GuildMaps, []),
    case lists:keyfind({RankType, GuildId}, #common_rank_guild.guild_key, RankList) of
        #common_rank_guild{} = CommonRankGuild ->
            NewCommonRankGuild = CommonRankGuild#common_rank_guild{guild_name = Name},
            NewRankList = lists:keyreplace({RankType, GuildId}, #common_rank_guild.guild_key, RankList, NewCommonRankGuild),
            db_common_rank_guild_save(NewCommonRankGuild),
            NewRankList2 = sort_rank_list(NewRankList);
        false ->
            NewRankList2 = RankList
    end,
    NewGuildMaps = maps:put(RankType, NewRankList2, GuildMaps),
    {ok, State#common_rank_state{guild_maps = NewGuildMaps}}.

rechange_guild_chief(State, GuildId,ChiefID,Name, RankTypeList)->
    F = fun(RankType, TempState) ->
        {ok, NewTmpState} = rechange_guild_chief_help(TempState, RankType, GuildId,ChiefID,Name),
        NewTmpState
        end,
    NewState = lists:foldl(F, State, RankTypeList),
    {ok, NewState}.

rechange_guild_chief_help(State, RankType, GuildId,ChiefID,Name) ->
    #common_rank_state{guild_maps = GuildMaps} = State,
    RankList = maps:get(RankType, GuildMaps, []),
    case lists:keyfind({RankType, GuildId}, #common_rank_guild.guild_key, RankList) of
        #common_rank_guild{} = CommonRankGuild ->
            NewCommonRankGuild = CommonRankGuild#common_rank_guild{chairman_id=ChiefID,chairman_name=Name},
            NewRankList = lists:keyreplace({RankType, GuildId}, #common_rank_guild.guild_key, RankList, NewCommonRankGuild),
            db_common_rank_guild_save(NewCommonRankGuild);
        false ->
            NewRankList = RankList
    end,
    NewGuildMaps = maps:put(RankType, NewRankList, GuildMaps),
    {ok, State#common_rank_state{guild_maps = NewGuildMaps}}.

%%20210428 不在对比排名 用活跃值
get_labor_rank(State, GuildID,Target)->
    #common_rank_state{guild_maps = GuildMaps} = State,
    RankType = ?RANK_TYPE_GUILD_LABOR_LAST,
    RankList = maps:get(RankType, GuildMaps, []),
    case lists:keyfind({RankType, GuildID}, #common_rank_guild.guild_key, RankList) of
        #common_rank_guild{value=GValue} ->
            skip;
        false ->
            GValue = 0
    end,
    case lists:keyfind({RankType, Target}, #common_rank_guild.guild_key, RankList) of
        #common_rank_guild{value=TValue} ->
            skip;
        false ->
            TValue = 0
    end,
    [GValue,TValue].

%% 更新平均等级
refresh_average_lv(State) ->
    #common_rank_state{ref_average_lv = Ref} = State,
    IsGmSet =  case catch ets:lookup(?SERVER_KV, ?SERVER_KV_IS_GM_WORLD_LV) of
        [KV] -> KV#server_kv.value;
        _ -> 0
    end,
    %% GM是否设置了世界等级，如果是本次不刷新世界等级
    case IsGmSet of
        0 ->
            OldWorldLv = util:get_world_lv(),
            RankList = get_rank_list_by_rank_type(?RANK_TYPE_LV),
            lib_server_kv:reset_world_lv(#{?RANK_TYPE_LV => RankList}),
            NewWorldLv = util:get_world_lv(),
            OldWorldLv =/= NewWorldLv andalso util:cast_event_to_players({'refresh_average_lv'});
        _ -> skip
    end,
    OpenDay = util:get_open_day(),
    OpenDayIntervals = data_key_value:get(2210001),
    LastTime = calc_click_time(OpenDay, OpenDayIntervals),
    NewRef = util:send_after(Ref, LastTime*1000, self(), {'refresh_average_lv'}),
    {ok, State#common_rank_state{ref_average_lv = NewRef}}.

calc_click_time(_OpDay,[])->
    86400;
calc_click_time(OpDay,[{D,C}|T])->
    case OpDay =< D of
        true -> C;
        _    -> calc_click_time(OpDay,T)
    end.

%% 刷新榜单
refresh_common_rank(State, RankType, CommonRankGuild) when RankType == ?RANK_TYPE_GUILD ->
    #common_rank_state{guild_maps = GuildMaps, rank_limit = RankLimit} = State,
    RankList = maps:get(RankType, GuildMaps, []),
    {NewRankList, NewRankLimit} = do_refresh_common_rank_help(RankList, RankType, CommonRankGuild, RankLimit),
    NewRankMaps = maps:put(RankType, NewRankList, GuildMaps),
    NewState = State#common_rank_state{guild_maps = NewRankMaps, rank_limit = NewRankLimit},
    {ok, NewState};
refresh_common_rank(State, RankType, CommonRankGuild) when RankType == ?RANK_TYPE_GUILD_LABOR ->
    #common_rank_state{guild_maps = GuildMaps, rank_limit = RankLimit} = State,
    RankList = maps:get(RankType, GuildMaps, []),
    {NewRankList, NewRankLimit} = do_refresh_common_rank_help(RankList, RankType, CommonRankGuild, RankLimit),
    NewRankMaps = maps:put(RankType, NewRankList, GuildMaps),
    NewState = State#common_rank_state{guild_maps = NewRankMaps, rank_limit = NewRankLimit},
    {ok, NewState};

refresh_common_rank(State, RankType, {RoleId, TotalNum})
 when RankType == ?RANK_TYPE_CHARM_WEEK orelse RankType == ?RANK_TYPE_GENEROURS ->
    #common_rank_state{rank_limit = RankLimit, first_top = FirstTop} = State,
    RankList = get_rank_list_by_rank_type(RankType),
    NewRole = #common_rank_role{role_key = {RankType, RoleId}, rank_type = RankType, role_id = RoleId, value = TotalNum, time = utime:unixtime()},
    {NewRankList, NewRankLimit} = do_refresh_common_rank_help(RankList, RankType, NewRole, RankLimit),
    FirstTopRankVal = get_first_top_rank_val(RankType, NewRole),
    NewFirstTop = refresh_rank_first_top(NewRole#common_rank_role.role_id, FirstTopRankVal, RankType, FirstTop),
    insert_rank_list(RankType, NewRankList),
    NewState = State#common_rank_state{rank_limit = NewRankLimit, first_top = NewFirstTop},
    {ok, NewState};

refresh_common_rank(State, RankType, CommonRankRole) ->
    #common_rank_state{rank_limit = RankLimit, first_top = FirstTop} = State,
    RankList = get_rank_list_by_rank_type(RankType),
    {NewRankList, NewRankLimit} = do_refresh_common_rank_help(RankList, RankType, CommonRankRole, RankLimit),
    FirstTopRankVal = get_first_top_rank_val(RankType, CommonRankRole),
    NewFirstTop = refresh_rank_first_top(CommonRankRole#common_rank_role.role_id, FirstTopRankVal, RankType, FirstTop),
    insert_rank_list(RankType, NewRankList),
    NewState = State#common_rank_state{rank_limit = NewRankLimit, first_top = NewFirstTop},
    {ok, NewState}.


%% 先判断list中是否存在key和value都相等的玩家，存在则跟新数据，不存在则将其进行队列排序：将其与队
%% 尾比较，若小于队尾并且队列长度大于最长长度，则丢弃，否则将其加入队列，排序并保证队列长度为最大
%% 队列长度，发送数据的时候，先截取显示长度，再判断是否满足limit，满足条件的才加入发送队列。
%% 时刻保证，排序之后队列和数据库保存的数据为整个服的前N，然后在这之中选择发送、
do_refresh_common_rank_help(RankList, RankType, CommonRankGuild, RankLimit) when is_record(CommonRankGuild,common_rank_guild)->
    #common_rank_guild{guild_key = GuildKey, value = Value, guild_name = _GuildName} = CommonRankGuild,
    #rank_config{} = lib_common_rank:get_rank_config(RankType),
    case lists:keyfind(GuildKey, #common_rank_guild.guild_key, RankList) of
        #common_rank_guild{time = Time, value = Value, guild_name = _OldGuildName, rank = Rank} = OldRankGuild -> %% 存在key和value都相等的
            NewGuild = CommonRankGuild#common_rank_guild{time = Time, rank = Rank},
            % ?PRINT("~p~n", [OldGuildName]),
            % ?PRINT("~p~n", [GuildName]),
            case NewGuild =/= OldRankGuild of
                true ->
                    db_common_rank_guild_save(NewGuild),
                    NewList = lists:keystore(GuildKey, #common_rank_guild.guild_key, RankList, NewGuild);
                _ ->
                    NewList = RankList
            end,
            {NewList, RankLimit};
        _ ->
            do_refresh_common_rank_help2(RankList, RankType, CommonRankGuild, RankLimit)
    end;

do_refresh_common_rank_help(RankList, RankType, CommonRankRole, RankLimit) ->
    #common_rank_role{role_key = RoleKey, value = Value} = CommonRankRole,
    case lists:keyfind(RoleKey, #common_rank_role.role_key, RankList) of
        #common_rank_role{value = Value, time = OldTime, rank = Rank, display_value = DisValue} = OldRankRole ->
            NewRole = CommonRankRole#common_rank_role{time = OldTime, rank = Rank, display_value = DisValue},  %% 时间为排序值更新时间 如果值没改变就用回之前的
            case NewRole =/= OldRankRole of   %% 保留值改了的时候更新
                true ->
                    db_common_rank_role_save(NewRole),
                    NewList = lists:keystore(RoleKey, #common_rank_role.role_key, RankList, NewRole);
                _ ->
                    NewList = RankList
            end,
            {NewList, RankLimit};
        _ ->
            do_refresh_common_rank_help2(RankList, RankType, CommonRankRole, RankLimit)
    end.

do_refresh_common_rank_help2(RankList, RankType, CommonRankGuild, RankLimit) when is_record(CommonRankGuild,common_rank_guild)->
    #rank_config{rank_max = MaxRankLen, rank_limit = Limit} = lib_common_rank:get_rank_config(RankType),
    Temp = maps:get(RankType, RankLimit, Limit),
    LastValue = max(Temp, Limit),
    %% ?PRINT("LastValue:~p RankList:~p ~n", [LastValue, RankList]),
    case RankList == [] of
        true -> %% 列表为空，且排序值高于阈值，加入队列
            if
                CommonRankGuild#common_rank_guild.value >= LastValue ->
                    db_common_rank_guild_save(CommonRankGuild),
                    NewRankList2 = [CommonRankGuild#common_rank_guild{rank = 1}],
                    {NewRankList2, RankLimit};
                true ->
                    NewRankList2 = [],
                    {NewRankList2, RankLimit}
            end;
        false ->
            IsExistKey = lists:keymember(CommonRankGuild#common_rank_guild.guild_key, #common_rank_guild.guild_key, RankList),
            %% Len = length(RankList),
            #common_rank_guild{guild_key = GuildKey, guild_name = _GuildName, value = Value} = CommonRankGuild,
            % ?PRINT("~w~n", [GuildName]),
            %% 是否需要排序
            case Value < LastValue andalso (not IsExistKey) of
                true -> %% 排序值小于阈值且不存在
                    NewRankList2 = RankList,
                    {NewRankList2, RankLimit};
                false ->
                    %% 内存和数据库存储
                    NewRankList = lists:keystore(GuildKey, #common_rank_guild.guild_key, RankList, CommonRankGuild),
                    db_common_rank_guild_save(CommonRankGuild),
                    %% 排序
                    NewRankList2 = sort_rank_list(NewRankList),
                    NewLen = length(NewRankList2),
                    case NewLen > MaxRankLen of
                        true -> LeftRankList = lists:nthtail(MaxRankLen, NewRankList2);
                        false -> LeftRankList = []
                    end,
                    %% 清理冗余数据,这样修改插入数据效率会提高
                    F = fun(#common_rank_guild{guild_id = TmpGuildId}) ->
                        db_common_rank_delete_by_id(RankType, TmpGuildId) end,
                    lists:foreach(F, LeftRankList),
                    %% 返回数据
                    LastList = lists:sublist(NewRankList2, MaxRankLen),
                    case LeftRankList of
                        [] ->
                            NewLastValue = LastValue;
                        _ ->
                            LastRankGuild = lists:last(LastList),
                            #common_rank_guild{value = TempLastValue} = LastRankGuild,
                            NewLastValue = max(TempLastValue, LastValue)
                    end,
                    NewRankLimit = maps:put(RankType, NewLastValue, RankLimit),
                    {LastList, NewRankLimit}
            end
    end;

do_refresh_common_rank_help2(RankList, RankType, CommonRankRole, RankLimit) ->
    #common_rank_role{role_key = RoleKey, value = Value, second_value = SecVal} = CommonRankRole,
    #rank_config{rank_max = _MaxRankLen, rank_limit = Limit} = lib_common_rank:get_rank_config(RankType),
    Temp = maps:get(RankType, RankLimit, Limit),
    LastValue = max(Temp, Limit),
    case RankList == [] of
        true ->
            if
                Value >= LastValue ->
                    db_common_rank_role_save(CommonRankRole),
                    {[CommonRankRole], RankLimit};
                true -> {[], RankLimit}
            end;
        false ->
            IsExistKey = lists:keymember(RoleKey, #common_rank_role.role_key, RankList),
            %% 是否需要插入数据
            case Value < LastValue andalso (not IsExistKey) of
                true -> {RankList, RankLimit};
                false ->
                    %% 内存和数据库存储
                    case lists:keyfind(RoleKey, #common_rank_role.role_key, RankList) of
                        false ->
                            NewRankList = [CommonRankRole | RankList],
                            db_common_rank_role_save(CommonRankRole);
                        #common_rank_role{rank = Rank, display_value = DisValue, value = OldValue, second_value = OldSecVal} ->
                            case  Value =< OldValue of  %% 历史最高
                                true ->
                                    IsPowerType = lists:member(RankType, ?RANK_TYPE_ALL_COMBATS),
                                    IsLvType    = lists:member(RankType, ?RANK_TYPE_ALL_LVS),
                                    if
                                        RankType == ?RANK_TYPE_DESIGNATION orelse RankType == ?RANK_TYPE_FASHION ->
                                            if OldSecVal == SecVal ->
                                                    NewRankList = RankList;
                                                true -> %% 收集榜数量变动更新
                                                    NewRankList = lists:keystore(RoleKey, #common_rank_role.role_key, RankList,
                                                        CommonRankRole#common_rank_role{rank = Rank, display_value = DisValue})
                                            end;
                                        not IsPowerType andalso not IsLvType ->
                                            NewRankList = RankList;
                                        true -> %% 战力榜&等级榜实时更新
                                            NewRankList = lists:keystore(RoleKey, #common_rank_role.role_key, RankList,
                                                CommonRankRole#common_rank_role{rank = Rank, display_value = DisValue})
                                    end;
                                false ->
                                    NewRankList = lists:keystore(RoleKey, #common_rank_role.role_key, RankList,
                                        CommonRankRole#common_rank_role{rank = Rank, display_value = DisValue}),
                                    db_common_rank_role_save(CommonRankRole)
                            end
                    end,
                    {NewRankList, RankLimit}
            end
    end.

%% 更新首度目标达成数据
refresh_rank_first_top(RoleId, RankVal, RankType, FirstTop) ->
    TargetTypes = data_ranking:get_all_target_type(),
    IsTargetType = lists:any(fun({Type, _Index}) -> Type == RankType end, TargetTypes),
    if
        not IsTargetType ->
            FirstTop;
        true ->
            Now = utime:unixtime(),
            TypeTargets = data_ranking:get_target_by_type(RankType),
            FilterTargets = lists:filter(fun({_Index, Target}) -> RankVal >= Target end, TypeTargets),
            {NewDbList, NewFirstTop} =
            lists:foldl(fun({Index1, _Target1}, {DbList, TempFirstTop}) ->
                case maps:get({RankType, Index1}, TempFirstTop, false) of
                    {_RoleIdX, _Time} ->
                        {DbList, TempFirstTop};
                    _ ->
                        NewTempFirstTop = maps:put({RankType, Index1}, {RoleId, Now}, TempFirstTop),
                        {[{RankType, Index1, RoleId, Now}|DbList], NewTempFirstTop}
                end
            end, {[], FirstTop}, FilterTargets),
            NewDbList =/=[] andalso db_batch_replace_rank_first_top(NewDbList),
            NewDbList =/= [] andalso notice_first_top_change(RankType),
            NewFirstTop
    end.

notice_first_top_change(RankType) ->
    {ok, BinData} = pt_221:write(22110, [RankType]),
    lib_server_send:send_to_all(BinData),
    ok.

%% 发送榜单列表
send_rank_list(State, RankType, Start, Len, RoleId, GuildId, SelSecondVal)->
    case lists:member(RankType,?RANK_GUILD_LIST) of
        true->
            send_guild_rank_list(State, RankType, Start, Len, RoleId, GuildId, SelSecondVal);
        _->
            send_role_rank_list(State, RankType, Start, Len, RoleId, GuildId, SelSecondVal)
    end.
send_guild_rank_list(State, RankType, Start, Len, RoleId, GuildId, _SelSecondVal)->
    #common_rank_state{guild_maps = RankMaps, praise_maps = PraiseMaps} = State,
    RankList = maps:get(RankType, RankMaps, []),
    Sum = length(RankList),
    case Start > Sum orelse Start =< 0 orelse Len =< 0 of
        true ->
            if
                Sum == 0 ->
                    {ok, BinData} = pt_221:write(22102, [RankType, 0, 0, "", 0, 0, 0, 0, []]),
                    lib_server_send:send_to_uid(RoleId, BinData);
                true -> skip
            end;
        _ ->
            %% 需要将活跃排行榜逆序(活跃值低的排在前面发送给前端)
            %% modify: 2021-07-01
            RankList1 = case lists:member(RankType, [?RANK_TYPE_GUILD_LABOR ,?RANK_TYPE_GUILD_LABOR_LAST]) of
                            true -> lists:reverse(RankList);
                            _ -> RankList
                        end,
            SubRankList = lists:sublist(RankList1, Start, Len),
            F = fun(#common_rank_guild{
                guild_id      = TmpGuildId,
                guild_name    = GuildName,
                flag          = Flag,
                chairman_id   = ChairmanId,
                chairman_name = ChairmanName,
                lv            = Lv,
                members_num   = MembersNum,
                value         = Value,
                second_value  = SecVal,
                rank          = Rank,
                add_mem_num   = AddMemNum
                ,create_time  = CreateTime
                ,labor_refresh_time = LastRefreshTime
            }) ->
                PraiseNum = maps:get({RankType, TmpGuildId}, PraiseMaps, 0),
                case lib_role:get_role_show(ChairmanId) of
                    [] -> Figure = #figure{}, SelCombat = 0;
                    #ets_role_show{figure = Figure, combat_power = SelCombat} -> skip
                end,
                OpenDay = util:get_open_day(),
                GuildLaborLvList = data_guild:get_active_lv(OpenDay),
                HasFirstRefresh = LastRefreshTime > CreateTime,
                Division = case HasFirstRefresh of
                               false -> 0;
                               _ -> lib_guild_mod:get_labor_lv(GuildLaborLvList, Value)
                           end,
                {TmpGuildId, GuildName, Flag, ChairmanId, ChairmanName,PraiseNum, Lv, MembersNum, Figure, SelCombat, Value,SecVal,Rank, AddMemNum, Division}
            end,
            SendList = lists:map(F, SubRankList),
            %% io:format("~n M:~p L:~p guild RankType:~p List:~p ~n", [?MODULE, ?LINE, RankType, List]),
            case lists:keyfind({RankType, GuildId}, #common_rank_guild.guild_key, RankList) of
                #common_rank_guild{rank = GuildRank, guild_name = GuildName, lv = Lv, members_num = MembersNum, value = Value} ->
                    skip;
                _ ->
                    GuildRank = 0, Lv = 0, MembersNum = 0, Value = 0, GuildName = ""
            end,
            {ok, BinData} = pt_221:write(22102, [RankType, GuildRank, GuildId, GuildName,Lv, MembersNum, Value, Sum, SendList]),
            lib_server_send:send_to_uid(RoleId, BinData)
    end.

send_role_rank_list(State, RankType, Start, Len, RoleId, TmpSelValue, _SelSecondVal) ->
    #common_rank_state{praise_maps = PraiseMaps} = State,
    TmpRankL = get_rank_list_by_rank_type(RankType),
    SelValue = TmpSelValue,
    RankList = [RankRole || RankRole <- TmpRankL, RankRole#common_rank_role.rank =/= 0],
    Sum = length(RankList),
    % ?ERR("~p ~p ~p", [Start, Sum, Len]),
    case Start > Sum orelse Start =< 0 orelse Len =< 0 of
        true ->
            if
                Sum == 0 ->
                    lib_server_send:send_to_uid(RoleId, pt_221, 22101, [RankType, 0, SelValue, _SelSecondVal, 0, []]);
                true -> skip
            end;
        _ ->
            SubRankList = lists:sublist(RankList, Start, Len),
            F = fun(#common_rank_role{role_id = TmpRoleId, display_value = Value, second_value = SecondValue, third_value = ThirdValue, extra_value = ExtraValues, rank = Rank}) ->
                case lib_role:get_role_show(TmpRoleId) of
                    [] -> Figure = #figure{};
                    #ets_role_show{figure = Figure} -> skip
                end,
                RoleCombat = Value,
                PraiseNum = maps:get({RankType, TmpRoleId}, PraiseMaps, 0),
                % ?ERR("~p ~p ~p", [RankType, Value, SecondValue]),
                ExtraValues1 = if RankType == ?RANK_TYPE_BABY -> ExtraValues;
                    true -> util:term_to_string(ExtraValues)
                end,
                {TmpRoleId, PraiseNum, Figure, RoleCombat, Value, SecondValue, ThirdValue, ExtraValues1, Rank}
                end,
            SendList = lists:map(F, SubRankList),
            IsPowerRank = lists:member(RankType, ?RANK_TYPE_ALL_COMBATS),
            case lists:keyfind({RankType, RoleId}, #common_rank_role.role_key, RankList) of
                #common_rank_role{rank = RoleRank, display_value = DisPlayVal, second_value = TSelSecondVal} ->
                    if
                        not IsPowerRank ->
                            LastSelValue = DisPlayVal,
                            SelSecondVal = ?IF(lists:member(RankType, ?SHOW_RANK_SECVAL_LIST), TSelSecondVal, _SelSecondVal);
                        true ->
                            LastSelValue = SelValue, SelSecondVal = _SelSecondVal
                    end;
                _ -> RoleRank = 0, LastSelValue = SelValue, SelSecondVal = _SelSecondVal
            end,
            % ?ERR("rank_type ~p self ~p ~p", [RankType, LastSelValue, SendList]),
            {ok, BinData} = pt_221:write(22101, [RankType, RoleRank, LastSelValue, SelSecondVal, Sum, SendList]),
            lib_server_send:send_to_uid(RoleId, BinData)
    end.

get_top_rank(RankType, Start, Len, State, Sid) ->
    TmpRankL = get_rank_list_by_rank_type(RankType),
    TmpRankL1 = [RankRoleX || RankRoleX <- TmpRankL, RankRoleX#common_rank_role.rank =/= 0],
    Sum = length(TmpRankL1),
    case Start > Sum orelse Start =< 0 orelse Len =< 0 of
        true ->
            lib_server_send:send_to_sid(Sid, pt_221, 22105, [RankType, []]);
        _ ->
            SubRankList = lists:sublist(TmpRankL1, Start, Len),
            RankList = [{RankRole#common_rank_role.role_id, RankRole#common_rank_role.rank} || RankRole <- SubRankList, RankRole#common_rank_role.rank =/= 0],
            lib_server_send:send_to_sid(Sid, pt_221, 22105, [RankType, RankList])
    end,
    {ok, State}.

get_rank_top_role(_State, RankType, Num) ->
    TmpRankL = get_rank_list_by_rank_type(RankType),
    TmpRankL1 = [{RankRoleX#common_rank_role.role_id, RankRoleX#common_rank_role.value, RankRoleX#common_rank_role.second_value} || RankRoleX <- TmpRankL, RankRoleX#common_rank_role.rank =/= 0],
    lists:sublist(TmpRankL1, Num).

get_first_top_info(Sid, RankType, RewardedTarget, State) ->
    #common_rank_state{first_top = FirstTop, first_top_role = TopRoles} = State,
    % TypeRankList = maps:get(RankType, RankMaps, []),
    TypeRankList = get_rank_list_by_rank_type(RankType),
    {NewTopRoles, DataL} = maps:fold(fun({RankTypeX, TargetX}, {RoleId, _Time}, {TempTopRoles, Acc}) ->
        if RankType == RankTypeX ->
                case lists:member(TargetX, RewardedTarget) of
                    true -> RewardState = 2;
                    _    -> RewardState = 1
                end,
                IsFosterType = lists:member(RankType, ?RANK_TYPE_FOSTER),
                RoleFigure = lib_role:get_role_figure(RoleId),
                {NewTempTopRoles, Score} =
                if
                    IsFosterType ->
                        case lists:keyfind(RoleId, #common_rank_role.role_id, TypeRankList) of
                            #common_rank_role{value = Value} ->
                                {TempTopRoles, Value};
                            _ ->
                                case lists:keyfind({RoleId, RankType, TargetX}, 1, TempTopRoles) of
                                    {_, Value} ->
                                        {TempTopRoles, Value};
                                    _ ->
                                        Type = lib_common_rank:get_foster_cell_by_rank_type(RankType),
                                        case catch db:get_one(?SQL_PLAYER_FOSTER_LV_GET, [RoleId, Type]) of
                                            Value when is_integer(Value) ->
                                                {lists:keystore({RoleId, RankType, TargetX}, 1, TempTopRoles, {{RoleId, RankType, TargetX}, Value}), Value};
                                            _ ->
                                                {TempTopRoles, 0}
                                        end
                                end
                        end;
                    true ->
                        case lists:keyfind(RoleId, #common_rank_role.role_id, TypeRankList) of
                            #common_rank_role{value = Value} ->
                                {TempTopRoles, Value};
                            _ -> {TempTopRoles, 0}
                        end
                end,
                {NewTempTopRoles, [{TargetX, RewardState, Score, RoleFigure}|Acc]};
            true ->
                {TempTopRoles, Acc}
        end
    end, {TopRoles, []}, FirstTop),
    {ok, BinData} = pt_221:write(22106, [RankType, DataL]),
    lib_server_send:send_to_sid(Sid, BinData),
    {ok, State#common_rank_state{first_top_role = NewTopRoles}}.

get_first_top_reward(RoleId, RankType, Target, State) ->
    #common_rank_state{first_top = FirstTop} = State,
    case maps:get({RankType, Target}, FirstTop, false) of
        {_, _} ->
            lib_player:apply_cast(RoleId, ?APPLY_CAST_STATUS, ?MODULE, role_get_first_top_reward, [RankType, Target]);
        _ ->
            lib_server_send:send_to_uid(RoleId, pt_221, 22107, [RankType, ?ERRCODE(err211_first_top_limit)])
    end,
    {ok, State}.

get_top_rank_list(Sid, RankType, State) ->
    TypeRankList = get_rank_list_by_rank_type(RankType),
    TopRankList  = lists:foldl(fun(Rank, Acc) ->
        case lists:keyfind(Rank, #common_rank_role.rank, TypeRankList) of
            #common_rank_role{role_id = RoleId, value = Value} ->
                Figure = lib_role:get_role_figure(RoleId),
                Score =
                case data_ranking:get_target_by_type(RankType) of
                    [_|_] -> Value;
                    _     -> 0
                end,
                [{RoleId, Figure, Score, Rank}|Acc];
            _ ->
                [{0, #figure{}, 0, Rank}|Acc]
        end
    end, [], [1,2,3,4,5]),
    {ok, BinData} = pt_221:write(22111, [RankType, TopRankList]),
    lib_server_send:send_to_sid(Sid, BinData),
    {ok, State}.

get_first_top_rank_val(RankType, CommonRankRole) ->
    case data_ranking:get_target_by_type(RankType) of
        [_|_] ->
            CommonRankRole#common_rank_role.value;
        _ -> 0
    end.

role_get_first_top_reward(Player, RankType, Target) ->
    #player_status{id = RoleId, sid = Sid, role_first_top = RoleFirstTop} = Player,
    case lists:member({RankType, Target}, RoleFirstTop) of
        true ->
            lib_server_send:send_to_sid(Sid, pt_221, 22107, [RankType, ?ERRCODE(reward_is_got)]),
            {ok, Player};
        _ ->
            case data_ranking:get_target_reward(RankType, Target) of
                Rewards = [_|_] ->
                    NewPlayer = lib_goods_api:send_reward(Player, Rewards, first_top_reward),
                    db:execute(?REPLACE_INTO_COMMON_RANK_FIRST_TOP, [RoleId, RankType, Target]),
                    NewRoleFirstTop = [{RankType, Target}|lists:delete({RankType, Target}, RoleFirstTop)],
                    NewPlayer1 = NewPlayer#player_status{role_first_top = NewRoleFirstTop},
                    lib_server_send:send_to_sid(Sid, pt_221, 22107, [RankType, ?SUCCESS]),
                    {ok, NewPlayer1};
                _ ->
                    lib_server_send:send_to_sid(Sid, pt_221, 22107, [RankType, ?FAIL]),
                    {ok, Player}
            end
    end.


%% 更新榜上部分数据
update_common_rank_data(RoleId, RankType, UpdateList, State) ->
    TmpRankL = get_rank_list_by_rank_type(RankType),
    case lists:keyfind({RankType, RoleId}, #common_rank_role.role_key, TmpRankL) of
        RankRole = #common_rank_role{} ->
            Fields = record_info(fields, common_rank_role),
            NewRankRole = do_update_common_rank_data(Fields, UpdateList, RankRole),
            db_common_rank_role_save(NewRankRole),
            NewTmpRankL = lists:keystore({RankType, RoleId}, #common_rank_role.role_key, TmpRankL, NewRankRole),
            insert_rank_list(RankType, NewTmpRankL),
            {ok, State};
        _ ->
            {ok, State}
    end.

do_update_common_rank_data(_, [], RankRole) -> RankRole;
do_update_common_rank_data(Fields, [{RecTag, Val}|Rest], RankRole) ->
    Index = ulists:index_of(RecTag, Fields),
    NewRankRole = setelement(Index+1, RankRole, Val),
    do_update_common_rank_data(Fields, Rest, NewRankRole).

%% 定时排序
timer_common_rank(RankType, State) ->
    #common_rank_state{rank_limit = LimitMaps} = State,
    #rank_config{rank_max = MaxRankLen, rank_limit = CfgLimit} = lib_common_rank:get_rank_config(RankType),
    RankList = get_rank_list_by_rank_type(RankType),
    NewRankList = sort_rank_list(RankList),
    case length(NewRankList) > MaxRankLen andalso MaxRankLen =/= 0 of
        true -> LeftRankList = lists:nthtail(MaxRankLen, NewRankList);
        false -> LeftRankList = []
    end,
    %% 清理冗余数据,这样修改插入数据效率会提高
    [db_common_rank_delete_by_id(RankType, TmpRoleId) || #common_rank_role{role_id = TmpRoleId} <- LeftRankList],
    %% 返回数据
    TmpList = lists:sublist(NewRankList, MaxRankLen),
    LastList = [RankRole#common_rank_role{display_value = RankRole#common_rank_role.value} || RankRole <- TmpList],
    case LeftRankList of
        [] -> NewLastValue = CfgLimit;
        _ ->
            LastRankRole = lists:last(LastList),
            #common_rank_role{value = NewLastValue} = LastRankRole
    end,
    NewLimitMaps = maps:put(RankType, max(CfgLimit, NewLastValue), LimitMaps),
    insert_rank_list(RankType, LastList),
    NewState = State#common_rank_state{rank_limit = NewLimitMaps},
    {ok, NewState}.

timer_refresh_common_rank_logic([], State) -> State;
timer_refresh_common_rank_logic([RankType|Rest], State) ->
    {ok, NewState} = timer_common_rank(RankType, State),
    timer_refresh_common_rank_logic(Rest, NewState).

%% 每天定时记录日志
day_clear(_DelaySec, State) ->

    %% LOG
    daily_log_top_rank(State),

    {ok, State}.

%% 周期结算涉及称号榜单
interval_refresh_dsgt_rank(State1) ->
    DelaySec = 60,
    %% 结算前刷新排行榜
    RankTypeList = calc_daily_account_rank_type(),
    F = fun(Type, TmpState1) ->
        {ok, TmpState2} = timer_common_rank(Type, TmpState1),
        TmpState2
    end,
    State = lists:foldl(F, State1, RankTypeList),
    #common_rank_state{guild_maps = GuildMaps, old_first_guild = OldGuildId} = State,
    %% 公会榜
    case lib_common_rank:get_title_id(?RANK_TYPE_GUILD) of
        0 -> NewGuildId = OldGuildId;
        GuildDstId ->
            case maps:get(?RANK_TYPE_GUILD, GuildMaps, []) of
                [] -> NewGuildId = 0;
                [No1CommonRankGuild | TmpList] ->
                    #common_rank_guild{guild_id = NewGuildId, guild_name = No1GuildName, value = No1GuildValue} = No1CommonRankGuild,
                    lib_chat:send_TV({all}, ?MOD_RANK, 2, [No1GuildName, GuildDstId]),
                    case TmpList of
                        [] -> lib_log_api:log_common_rank_guild(NewGuildId, 1, No1GuildValue, 0, 0);
                        [No2CommonRankGuild | _] ->
                            #common_rank_guild{guild_id = No2GuildId, value = No2GuildValue} = No2CommonRankGuild,
                            lib_log_api:log_common_rank_guild(NewGuildId, 1, No1GuildValue, No2GuildId, No2GuildValue)
                    end
            end,
            spawn(fun() ->
                util:multiserver_delay(DelaySec, mod_guild, send_guild_rank_reward, [OldGuildId, NewGuildId, GuildDstId])
                  end)
    end,
    %% 其他个人榜单
    RankList = lists:map(fun(RankTypeX) ->
        {RankTypeX, get_rank_list_by_rank_type(RankTypeX)}
    end, RankTypeList),
    RankMaps = maps:from_list(RankList),
    spawn(fun() ->
        util:multiserver_delay(DelaySec, common_rank_logic, send_dsgt_account_reward, [RankTypeList, RankMaps])
          end),

    %% 更新state
    NewState = State#common_rank_state{old_first_guild = NewGuildId},
    NewState.

%% 判断需要日常结算称号的榜单
calc_daily_account_rank_type() ->
    AccountRankType = lists:filter(fun(RankType) ->
        case lib_common_rank:get_title_id(RankType) of
            Title when Title =/= 0 ->
                true;
            _ ->
                false
        end
    end, ?RANK_TYPE_LIST),
    [?RANK_TYPE_GUILD] ++ AccountRankType.


timer_update(State)->
    trigger_guild_badge(State),
    {ok,State}.


daily_timer(Type, State)->
    Day =  utime:day_of_week(),
    OpenDay = util:get_open_day(),
    NewState = case Type of
        ?FOUR when OpenDay>=?OPENDAY_BADGE, Day == ?WEEKDAY_BADGE->
            % trigger_guild_badge(State),
            exchange_guild_labor_rank(State);
        ?FOUR when Day =:= 1 orelse Day =:= 5 ->
            exchange_guild_labor_rank(State);
        _->
            State
    end,
    {ok, NewState}.

daily_log_top_rank(_State) ->
    RankList = lists:map(fun(RankType) ->
        {RankType, get_rank_list_by_rank_type(RankType)}
    end, ?RANK_TYPE_LIST),
    RankMaps = maps:from_list(RankList),
    Now = utime:unixtime(),
    spawn(fun() ->
        timer:sleep(600000),
        ta_rank_ret(RankMaps),
        log_common_rank_role_top(RankMaps, Now)
    end),
    ok.

log_common_rank_role_top(RankMaps, Now) ->
    lists:map(fun(RankType) ->
        case lists:member(RankType, ?RANK_TYPE_CAREER) of
            true -> skip;
            _    ->
                RankData = maps:get(RankType, RankMaps, []),
                log_common_rank_role_top(RankData, Now, 1)
        end
    end, ?RANK_TYPE_LIST),
    ok.

log_common_rank_role_top([], _, _) -> skip;
log_common_rank_role_top([_|_], _Now, Index) when Index > 50 ->
    skip;
log_common_rank_role_top([R|Rest], Now, Index) ->
    if Index rem 10 == 0 -> timer:sleep(300);
        true -> skip
    end,
    #common_rank_role{rank_type = RankType, role_id = RoleId, value = Val, rank = Rank} = R,
    #figure{name = Name, career = Career} = lib_role:get_role_figure(RoleId),
    lib_log_api:log_rank([RoleId, Name, Career, RankType, Rank, Val, Now]),
    log_common_rank_role_top(Rest, Now, Index+1).

ta_rank_ret(RankMaps) ->
    lists:map(fun(RankType) -> 
        RankList = maps:get(RankType, RankMaps, []),
        ta_rank_ret_1(RankType, RankList, 1)
    end, [?RANK_TYPE_COMBAT, ?RANK_TYPE_LV]),
    ok.

ta_rank_ret_1(_, [], _) -> skip;
ta_rank_ret_1(RankType, [#common_rank_role{role_id = RoleId, rank = Rank}|Rest], Index) ->
    if Index rem 10 == 0 -> timer:sleep(500);
        true -> skip
    end,
    lib_player:apply_cast(RoleId, ?APPLY_CAST_STATUS, ?HAND_OFFLINE, ?MODULE, role_ta_rank_ret_1, [RankType, Rank]),
    ta_rank_ret_1(RankType, Rest, Index+1).

role_ta_rank_ret_1(Player, RankType, Rank) ->
    #player_status{id = RoleId, last_login_time = LastLoginTime, figure = #figure{guild_id = GuildId, guild_name = GuildName}} = Player,
    EventType = case RankType of
        ?RANK_TYPE_COMBAT -> power_rank;
        ?RANK_TYPE_LV     -> level_rank
    end,
    if LastLoginTime == 0 ->
            #ets_role_show{last_login_time = CacheLastLoginTime} = lib_role:get_role_show(RoleId),
            Time = CacheLastLoginTime;
        true -> Time = LastLoginTime
    end,
    ta_agent_fire:ta_rank(Player, [EventType, Rank, GuildId, GuildName, Time]),
    {ok, Player}.

gm_daily_timer(State)->
    trigger_guild_badge(State),
    NewState = exchange_guild_labor_rank(State),
    {ok, NewState}.


%%更新战力榜在线离线数据
change_online_flag(State,RoleID,OnLine,OffTime) ->
    RankL = get_rank_list_by_rank_type(?RANK_TYPE_COMBAT),
    case lists:keyfind({?RANK_TYPE_COMBAT, RoleID}, #common_rank_role.role_key, RankL) of
        false ->
            NewRankL = RankL;
        RankD ->
            #common_rank_role{off_time=OldOffTime}=RankD,
            NewRankD = RankD#common_rank_role{online=OnLine,off_time=OffTime},
            (OffTime-OldOffTime)>=1800 andalso db_common_rank_role_save(NewRankD),
            NewRankL = lists:keystore({?RANK_TYPE_COMBAT, RoleID}, #common_rank_role.role_key, RankL,NewRankD)
    end,
    insert_rank_list(?RANK_TYPE_COMBAT, NewRankL),
    {ok, State}.

%% 转性别后更新性别相关榜单
change_rank_by_type(State, RoleId,  OldType, RankType) ->
    DelRankL = get_rank_list_by_rank_type(OldType),
    AddRankL = get_rank_list_by_rank_type(RankType),
    case lists:keyfind({OldType, RoleId}, #common_rank_role.role_key, DelRankL) of
        false -> NewDelRankL = DelRankL, NewAddRankL = AddRankL;
        DelRankRole ->
            TmpDelRankL = lists:keydelete({OldType, RoleId}, #common_rank_role.role_key, DelRankL),
            TmpAddRankL = lists:keystore({RankType, RoleId}, #common_rank_role.role_key, AddRankL,
                DelRankRole#common_rank_role{role_key = {RankType, RoleId}, rank_type = RankType, rank = 0}),
            SortDelRankL = sort_rank_list(TmpDelRankL),
            SortAddRankL = sort_rank_list(TmpAddRankL),
            % 同步显示值
            NewDelRankL = [ TmpRole#common_rank_role{display_value =TmpRole#common_rank_role.value} || TmpRole <- SortDelRankL ],
            NewAddRankL = [ TmpRole#common_rank_role{display_value =TmpRole#common_rank_role.value} || TmpRole <- SortAddRankL ]
    end,
    insert_rank_list(OldType, NewDelRankL),
    insert_rank_list(RankType, NewAddRankL),
    {ok, State}.

%% 修复装备榜
gm_repair_equip_rank(State) ->
    {ok, State}.

%% 只对没有装备套装战力记录的玩家进行修复
repair_equip_rank(CommonRankRole) when CommonRankRole#common_rank_role.second_value == 0 ->
    #common_rank_role{role_id = RoleId} = CommonRankRole,
    case lib_player:is_online_global(RoleId) of
        true -> % 玩家在线直接获取最新数值
            lib_player:apply_cast(RoleId, ?APPLY_CAST_STATUS, lib_common_rank_api, refresh_rank_by_equip, []),
            CommonRankRole;
        false -> % 从玩家离线信息获取
            CommonRankRole
    end;
repair_equip_rank(CommonRankRole) -> CommonRankRole.

apply_cast(State, M, F, A) ->
    M:F(State, A).

gm_reset_first_top(State, _) ->
    db:execute(<<"DELETE FROM common_rank_first_top">>),
    db:execute(<<"DELETE FROM role_first_top_reward">>),
    util:cast_event_to_players({'apply_cast', ?APPLY_CAST_SAVE, ?MODULE, role_reset_first_top, []}),
    NewState = State#common_rank_state{first_top = maps:new()},
    {ok, NewState}.

role_reset_first_top(Player) ->
    NewPlayer = Player#player_status{role_first_top = []},
    {ok, NewPlayer}.

%%------------------------inside fun-------------------%%

%% 发送榜单称号奖励
send_dsgt_account_reward(RankTypeList, RankMaps) ->
    OpenLv = lib_module:get_open_lv(?MOD_RANK, 1),
    F = fun(RankType) ->
        RankList = maps:get(RankType, RankMaps, []),
        if
            RankList == [] -> skip;
            true ->
                case lists:keyfind(1, #common_rank_role.rank, RankList) of
                    #common_rank_role{role_id = No1RoleId, value = No1Value} ->
                        case lib_role:get_role_show(No1RoleId) of
                            [] -> ?ERR("common rank can not find the role info:~p~n", [[No1RoleId, RankType]]), skip;
                            #ets_role_show{figure = #figure{name = Name, lv = RoleLv, sex = Sex}} when RoleLv >= OpenLv ->
                                case lib_common_rank:get_title_id(RankType, Sex) of
                                    0 ->
                                        skip;
                                    DstId ->
                                        % ?ERR("~p ~p ~p", [RankType, No1RoleId, DstId]),
                                        lib_designation_api:active_dsgt_common(No1RoleId, DstId),
                                        RankName = lib_common_rank:get_rank_type_name(RankType),
                                        TitleName = lib_common_rank:get_title_name(RankType),
                                        lib_chat:send_TV({all}, ?MOD_RANK, 1, [Name, RankName, TitleName]),
                                        %% 日志
                                        case lists:keyfind(2, #common_rank_role.rank, RankList) of
                                            false -> lib_log_api:log_common_rank_role(No1RoleId, RankType, 1, No1Value, 0, 0);
                                            #common_rank_role{role_id = No2RoleId, value = No2Value} ->
                                                lib_log_api:log_common_rank_role(No1RoleId, RankType, 1, No1Value, No2RoleId, No2Value)
                                        end
                                end;
                            _ -> skip
                        end;
                    false -> ?ERR("ranklist not sort.~n", []), skip
                end
        end
        end,
    [F(X) || X <- RankTypeList].

%% 点赞
rank_praise(State, RoleId, OtId, RankType) when RankType == ?RANK_TYPE_GUILD ->
    #common_rank_state{guild_maps = GuildMaps} = State,
    RankList = maps:get(RankType, GuildMaps, []),
    case lists:keyfind({?RANK_TYPE_GUILD, OtId}, #common_rank_guild.guild_key, RankList) of
        false ->
            Res = false;
        _ ->
            Res = true
    end,
    do_rank_praise(State, RoleId, RankType, OtId, Res);
rank_praise(State, RoleId, OtRoleId, RankType) ->
    RankList = get_rank_list_by_rank_type(RankType),
    case lists:keyfind({RankType, OtRoleId}, #common_rank_role.role_key, RankList) of
        false ->
            Res = false;
        _ ->
            Res = true
    end,
    do_rank_praise(State, RoleId, RankType, OtRoleId, Res).

do_rank_praise(State, RoleId, RankType, OtRoleId, Res) ->
    #common_rank_state{praise_maps = PraiseMaps} = State,
    OldNum = maps:get({RankType, OtRoleId}, PraiseMaps, 0),
    case Res of
        true ->
            Code = ?SUCCESS,
            NewNum = OldNum + 1,
            NewMaps = maps:put({RankType, OtRoleId}, NewNum, PraiseMaps),
            db_common_rank_praise_save(RankType, OtRoleId, NewNum),
            lib_player:apply_cast(RoleId, ?APPLY_CAST_STATUS, lib_common_rank, role_rank_praise_update, [RankType, OtRoleId]),
            lib_daily:increment_offline(RoleId, ?MOD_RANK, ?RANK_DAILY_PRAISE, RankType),
            lib_activitycalen_api:role_success_end_activity(RoleId, ?MOD_RANK, ?MOD_SUB_RANK_PRAISE),
            NewState = State#common_rank_state{praise_maps = NewMaps},
            send_praise_reward(RoleId);
        _ ->
            Code = ?FAIL,
            NewNum = OldNum,
            NewState = State
    end,
    {ok, BinData} = pt_221:write(22104, [Code, RankType, OtRoleId, NewNum]),
    lib_server_send:send_to_uid(RoleId, BinData),
    {ok, NewState}.

send_praise_reward(RoleId) ->
    case data_ranking:get_value(fabulous_rewards) of
        Rewards = [_|_] ->
            Produce = #produce{reward = Rewards, type = rank_praise, subtype = 0, show_tips = 1,
                       title = utext:get(221007), content = utext:get(221008)},
            lib_goods_api:send_reward_with_mail(RoleId, Produce, ?MOD_RANK);
        _ ->
            skip
    end.

send_designation(RankType, RankList, NewList) ->
    [No1CommonRR | TmpLastList] = NewList, % 新的首位
    #common_rank_role{role_id = No1RoleId, value = No1Value} = No1CommonRR,
    case lists:keyfind(1, #common_rank_role.rank, RankList) of
        #common_rank_role{role_id = No1RoleId} -> skip;  % 首位没更改
        _ ->
            lib_designation_api:active_dsgt_common(No1RoleId, lib_common_rank:get_title_id(RankType)),
            lib_chat:send_TV({all}, ?MOD_RANK, 1,
                [lib_common_rank:get_id_name(No1RoleId), lib_common_rank:get_rank_type_name(RankType), lib_common_rank:get_title_name(RankType)]),
            case TmpLastList of
                [] ->
                    lib_log_api:log_common_rank_role(No1RoleId, RankType, 1, No1Value, 0, 0);
                _ ->
                    [#common_rank_role{role_id = No2RoleId, value = No2Value} | _] = TmpLastList,
                    lib_log_api:log_common_rank_role(No1RoleId, RankType, 1, No1Value, No2RoleId, No2Value)
            end
    end.

local_rank_upload(RankTypeList, State) ->
    ServerId = config:get_server_id(),
    ServerNum = config:get_server_num(),
    lists:map(fun(RankType) ->
        RankL = get_rank_list_by_rank_type(RankType),
        RankL1 = [begin
            #figure{vip = Vip, sup_vip = SupVip, name = RoleName, sex = Sex} = lib_role:get_role_figure(RankRole#common_rank_role.role_id),
            #cross_common_rank_role{
                role_key = RankRole#common_rank_role.role_key,
                rank_type = RankType, server_num = ServerNum,
                server_id = ServerId, role_id = RankRole#common_rank_role.role_id,
                value = RankRole#common_rank_role.value,
                second_value = RankRole#common_rank_role.second_value,
                vip = Vip, sup_vip = SupVip, name = RoleName, gender = Sex
            } end || RankRole <- RankL, RankRole#common_rank_role.rank =/= 0],
        AfterZip = zlib:zip(util:term_to_bitstring({RankType, RankL1})),
        clusters_node:apply_cast(cross_rank_mgr, local_rank_upload_callback, [ServerId, AfterZip])
    end, RankTypeList),
    {ok, State}.

send_top_rank_info(State) ->
    F = fun(RankType) ->
        TmpRankL = get_rank_list_by_rank_type(RankType),
        SubRankL = lists:sublist(TmpRankL, 10),
        RankList = [{RankRole#common_rank_role.role_id, RankRole#common_rank_role.rank} || RankRole <- SubRankL, RankRole#common_rank_role.rank =/= 0],
        RankList
        end,
    RankInfo = lists:map(F,[?RANK_TYPE_LV,?RANK_TYPE_COMBAT]),
    mod_chat_agent:update_rank_info(RankInfo),
    {ok, State}.

send_top_30_combat_rank(RolePid,State) ->
    TmpRankL = get_rank_list_by_rank_type(?RANK_TYPE_COMBAT),
    SubRankL = lists:sublist(TmpRankL, 30),
    IdList = [RankRole#common_rank_role.role_id || RankRole <- SubRankL, RankRole#common_rank_role.rank =/= 0],
    lib_player:apply_cast(RolePid, ?APPLY_CAST_SAVE, mate_logic, supply_mate_list, [IdList]),
    {ok, State}.

%%-----------------------db------------------------------%%
db_common_rank_role_select() ->
    Sql = io_lib:format(?sql_common_rank_role_select, []),
    db:get_all(Sql).

db_common_rank_guild_select() ->
    Sql = io_lib:format(?sql_common_rank_guild_select, []),
    db:get_all(Sql).

db_common_rank_praise_select() ->
    Sql = io_lib:format(?sql_common_rank_praise_select, []),
    db:get_all(Sql).

db_common_rank_first_top() ->
    Sql = io_lib:format(?sql_common_rank_first_top_select, []),
    db:get_all(Sql).

db_common_rank_guild_save(RankRole) ->
    #common_rank_guild{
        rank_type     = RankType,
        guild_id      = GuildId,
        guild_name    = GuildName,
        flag          = Flag,
        chairman_id   = ChairmanId,
        chairman_name = ChairmanName,
        lv            = Lv,
        members_num   = MembersNum,
        value         = Value,
        second_value  = SecondValue,
        third_value   = ThirdValue,
        time          = Time
    } = RankRole,
    GuildName_B = util:make_sure_binary(GuildName),
    ChairmanName_B = util:make_sure_binary(ChairmanName),
    Sql = io_lib:format(?sql_common_rank_guild_save,
        [RankType, GuildId, GuildName_B,Flag,ChairmanId, ChairmanName_B, Lv, MembersNum, Value, SecondValue, ThirdValue, Time]),
    db:execute(Sql).

db_common_rank_role_save(RankRole) ->
    #common_rank_role{
        rank_type    = RankType,
        role_id      = RoleId,
        value        = Value,
        second_value = SecondValue,
        third_value  = ThirdValue,
        extra_value  = ExtraValue,
        time         = Time,
        off_time     = OffTime
    } = RankRole,
    if RankType == ?RANK_TYPE_BABY ->
            ExtraValue1 = util:make_sure_binary(ExtraValue);
        true ->
            ExtraValue1 = util:term_to_bitstring(ExtraValue)
    end,
    Sql = io_lib:format(?sql_common_rank_role_save,
        [RankType, RoleId, Value, SecondValue, ThirdValue, ExtraValue1, Time, OffTime]),
    db:execute(Sql).

db_common_rank_praise_save(PraiseType, Id, Num) ->
    Sql = io_lib:format(?sql_common_rank_praise_save,
        [PraiseType, Id, Num]),
    db:execute(Sql).

db_common_rank_delete_by_id(RankType, GuildId) when RankType == ?RANK_TYPE_GUILD ->
    Sql = io_lib:format(?sql_common_rank_guild_delete_by_guild_id, [RankType, GuildId]),
    db:execute(Sql);
db_common_rank_delete_by_id(RankType, GuildId) when RankType == ?RANK_TYPE_GUILD_LABOR ->
    Sql = io_lib:format(?sql_common_rank_guild_delete_by_guild_id, [RankType, GuildId]),
    db:execute(Sql);
db_common_rank_delete_by_id(RankType, GuildId) when RankType == ?RANK_TYPE_GUILD_LABOR_LAST ->
    Sql = io_lib:format(?sql_common_rank_guild_delete_by_guild_id, [RankType, GuildId]),
    db:execute(Sql);
db_common_rank_delete_by_id(RankType, RoleId) ->
    Sql = io_lib:format(?sql_common_rank_role_delete_by_role_id, [RankType, RoleId]),
    db:execute(Sql).

db_common_rank_delete_by_value(RankType, Value) when RankType == ?RANK_TYPE_GUILD ->
    Sql = io_lib:format(?sql_common_rank_guild_delete_by_value, [RankType, Value]),
    db:execute(Sql);
db_common_rank_delete_by_value(RankType, Value) when RankType == ?RANK_TYPE_GUILD_LABOR ->
    Sql = io_lib:format(?sql_common_rank_guild_delete_by_value, [RankType, Value]),
    db:execute(Sql);
db_common_rank_delete_by_value(RankType, Value) when RankType == ?RANK_TYPE_GUILD_LABOR_LAST ->
    Sql = io_lib:format(?sql_common_rank_guild_delete_by_value, [RankType, Value]),
    db:execute(Sql);
db_common_rank_delete_by_value(RankType, Value) ->
    Sql = io_lib:format(?sql_common_rank_role_delete_by_value, [RankType, Value]),
    db:execute(Sql).

db_batch_replace_rank_first_top(NewDbList) ->
    DataStrList = [util:fmt_bin(<<"(~p, ~p, ~p, ~p)">>, [RankType, Target, RoleId, Time]) || {RankType, Target, RoleId, Time} <- NewDbList],
    DataStrAll  = util:join_bitstring(DataStrList, <<",">>),
    SqlReplace  = util:fmt_bin(?SQL_COMMON_RANK_FIRST_TOP, [DataStrAll]),
    db:execute(SqlReplace).

%%激活社团榜单徽章
trigger_guild_badge(State)->
    #common_rank_state{guild_maps = RankMaps} = State,
    RankList  = maps:get(?RANK_TYPE_GUILD, RankMaps, []),
    RankList1 = maps:get(?RANK_TYPE_GUILD_LABOR,RankMaps,[]),
    lib_guild_badge:trigger_badge_event(RankList,1),
    lib_guild_badge:trigger_badge_event(RankList1,6).


%%清理上期社团活跃榜
%%把最新即时数据拷贝到上期数据
exchange_guild_labor_rank(State)->
    #common_rank_state{guild_maps = RankMaps} = State,
    RankList0 = maps:get(?RANK_TYPE_GUILD_LABOR, RankMaps, []),
    RankList1 = [RData#common_rank_guild{value=0} ||RData<-RankList0],
    RankMaps0 = maps:put(?RANK_TYPE_GUILD_LABOR,RankList1,RankMaps),
    RankList = [begin
        #common_rank_guild{guild_id=Gid}=RData,
        RData#common_rank_guild{guild_key={?RANK_TYPE_GUILD_LABOR_LAST,Gid},rank_type=?RANK_TYPE_GUILD_LABOR_LAST}
    end ||RData<-RankList0],
    NewRankMaps = maps:put(?RANK_TYPE_GUILD_LABOR_LAST, RankList,RankMaps0),
    db:execute(io_lib:format(?SQL_COMMON_GUILD_RANK_DEL_TYPE, [?RANK_TYPE_GUILD_LABOR_LAST])),
    db:execute(io_lib:format(?SQL_COMMON_GUILD_RANK_DEL_TYPE, [?RANK_TYPE_GUILD_LABOR])),
    db_common_guild_rank_batch(RankList),
    db_common_guild_rank_batch(RankList1),
    State#common_rank_state{guild_maps = NewRankMaps}.



db_common_guild_rank_batch([])->
    ignore;
db_common_guild_rank_batch(RankList)->
    DataStrList = [format_bin_string(RankData) || RankData <- RankList],
    DataStrAll  = util:join_bitstring(DataStrList, <<",">>),
    SqlReplace  = util:fmt_bin(?SQL_COMMON_GUILD_RANK_BATCH, [DataStrAll]),
    db:execute(SqlReplace).

format_bin_string(RankData)->
    #common_rank_guild{
        rank_type    = RankType,
        guild_id     = Gid,
        guild_name   = GName0,
        flag         = Flag,
        chairman_id  = Cid,
        chairman_name= CName0,
        lv           = Lv,
        members_num  = MNum,
        value        = Value,
        second_value = SecondValue,
        third_value  = ThirdValue,
        time         = Time
    } = RankData,
    GName = util:make_sure_binary(GName0),
    CName = util:make_sure_binary(CName0),
    util:fmt_bin(<<"(~p,~p,'~ts',~p,~p,'~ts', ~p, ~p, ~p, ~p, ~p, ~p)">>,
     [RankType, Gid,GName,Flag,Cid,CName,Lv,MNum,Value,SecondValue,ThirdValue,Time]).

%% --------------------------------------------------------------------------------------
%% 同步社团进程的创建时间和上次刷新活跃值时间
sync_guild_create_time() ->
    GuildMap = lib_guild_data:get_guild_map(),
    GuildList = lib_guild_mod:get_guild_list(GuildMap, 0),
    SynGuildMsg = [{GuildId, CreateTime, RefreshTime}||#guild{id = GuildId, create_time = CreateTime, week_labor_refresh = RefreshTime}<-GuildList],
    mod_common_rank:apply_cast(?MODULE, sync_guild_create_time_core, [?RANK_TYPE_GUILD_LABOR, SynGuildMsg]),
    mod_common_rank:apply_cast(?MODULE, sync_guild_create_time_core, [?RANK_TYPE_GUILD_LABOR_LAST, SynGuildMsg]),
    ok.

sync_guild_create_time_core(State, [RankType, SynGuildMsg]) ->
    #common_rank_state{guild_maps = RankMaps} = State,
    RankList = maps:get(RankType, RankMaps, []),
    F = fun({GuildId, CreateTime, RefreshTime}, TRankList) ->
        case lists:keyfind({RankType, GuildId}, #common_rank_guild.guild_key, TRankList) of
            #common_rank_guild{} = CommonRankGuild ->
                NewCommonRankGuild = CommonRankGuild#common_rank_guild{
                    create_time = CreateTime
                    ,labor_refresh_time = RefreshTime
                },
                lists:keystore({RankType, GuildId}, #common_rank_guild.guild_key, TRankList, NewCommonRankGuild);
            _ ->
                TRankList
        end end,
    NewRankList = lists:foldl(F, RankList, SynGuildMsg),
    NewRankMaps = maps:put(RankType, NewRankList, RankMaps),
    {ok, State#common_rank_state{guild_maps = NewRankMaps}}.
