%% ---------------------------------------------------------------------------
%% @doc 巅峰竞技util模块
%% @author hek
%% @since  2016-11-14
%% @deprecated
%% ---------------------------------------------------------------------------
-module(lib_top_pk_util).
-include("role.hrl").
-include("common.hrl").
-include("server_kv.hrl").
-include("top_pk.hrl").
-include("figure.hrl").
-include("def_fun.hrl").
-include("def_module.hrl").
-include("def_gen_server.hrl").

-export([
    apply_cast/4,               %% 跨节点cast方式执行MFA
    get_activity_enabled/0,     %% 获取活动是否开启
    get_keyvalues/1,            %% 获取常量配置
    get_cur_season_id/0,        %% 获取赛季id
    get_season_start_time/0,    %% 获取赛季开始时间
    get_season_end_time/0,      %% 获取赛季结束时间
    get_season_world_lv/0,      %% 获取赛季世界等级
    get_season_settle_num/0,    %% 获取赛季结算次数
    unpacket_role_rank/1,       %% 解包排行榜
    pack_role_rank/1,           %% 打包排行榜
    sort_rank_list/1,           %% 对玩家数据进行排序
    check_up/2,                 %% 检测能否上榜，积分>时间
    refresh_rank/2,             %% 刷新玩家排行
    update_rank_role/3          %% 更新排行榜玩家信息
]).
-export([
    db_select_player_top_pk/1,
    db_select_player_top_pk_for_rank/0,
    db_replace_into_player_top_pk/2,
    db_truncate_player_top_pk/0,
    db_select_rank_center/0,
    db_truncate_rank_center/0,
    db_save_rank_center/1
]).

%% 跨节点cast方式执行MFA
apply_cast(Node, Mod, Fun, Args) ->
    if
        Node =:= node() -> erlang:apply(Mod, Fun, Args);
        true -> rpc:cast(Node, Mod, Fun, Args)
    end.

%% 获取活动是否开启
get_activity_enabled() ->
    case lib_activitycalen_api:get_first_enabled_ac_id(?MOD_TOPPK, 0) of
        {ok, _} -> true;
        _ -> false
    end.

%% 获取常量配置
get_keyvalues(Id) ->
    case data_top_pk:get_keyvalues(Id) of
        #base_top_pk_keyvalues{value = Value} -> Value;
        _ -> 0
    end.

%% 获取赛季id
get_cur_season_id() ->
    {SeasonId, _StartTime, _EndTime} = get_season_info(),
    SeasonId.

%% 获取赛季开始时间
get_season_start_time() ->
    {_SeasonId, StartTime, _EndTime} = get_season_info(),
    StartTime.

%% 获取赛季结束时间
get_season_end_time() ->
    {_SeasonId, _StartTime, EndTime} = get_season_info(),
    EndTime.

%% 获取赛季信息
%% @return {SeasonId, StartTime, EndTime}
get_season_info() ->
    NowTime = utime:unixtime(),
    {Year, Mon, Day} = ?TOP_PK_KV_FIRST_SEASON_OPEN_DATE,
    SeasonDuration = ?TOP_PK_KV_SEASON_DURATION,
    FirstSeasonOpenTime = utime:unixtime({{Year, Mon, Day}, {0, 0, 0}}),
    SeasonId = (NowTime - FirstSeasonOpenTime) div (SeasonDuration*?ONE_DAY_SECONDS) + 1,
    LastSeasonId = max(SeasonId, 0),
    StartTime = FirstSeasonOpenTime + (LastSeasonId-1)*SeasonDuration*?ONE_DAY_SECONDS,
    EndTime = StartTime + SeasonDuration*?ONE_DAY_SECONDS -1,
    {LastSeasonId, StartTime, EndTime}.

%% 获取赛季世界等级
get_season_world_lv() ->
    case lib_server_kv:get_value(?SERVER_KV_TOP_PK_WORLD_LV, 0) of
        0 -> util:get_world_lv();
        WorldLv -> WorldLv
    end.

%% 获取赛季结算次数
get_season_settle_num() ->
    case lib_server_kv:get_value(?SERVER_KV_TOP_PK_SEASON_SETTLE_NUM, 0) of
        0 -> 0;
        SettleNum -> SettleNum
    end.

%% ---------------------------------------------------------------------------
%% @doc 解包排行榜
unpacket_role_rank([]) -> [];
unpacket_role_rank(Msg) ->
    <<Length:8, Bin/binary>> = zlib:uncompress(Msg),
    unpacket_role(Length, Bin, []).

unpacket_role(Length, Bin, Rank) when Length > 0->
    <<RoleId:64, Rest1/binary>> = Bin,
    {RoleName, Rest2} = pt:read_string(Rest1),
    <<Career:8, Power:32, Rest3/binary>> = Rest2,
    {Platform, Rest4} = pt:read_string(Rest3),
    <<ServerNum:16, RankId:16, Score:32, PkTime:32, Rest5/binary>> = Rest4,
    One = #rank_role{
        role_id = RoleId, role_name = RoleName, career = Career, power = Power, platform = Platform,
        server_num = ServerNum, rank_id = RankId, score = Score, pk_time = PkTime},
    unpacket_role(Length - 1, Rest5, [One|Rank]);
unpacket_role(_, _, Rank) -> Rank.

%% ---------------------------------------------------------------------------
%% @doc 打包排行榜
pack_role_rank([]) -> [];
pack_role_rank(Rank) ->
    Len = length(Rank),
    Packet = pack_role(Rank, []),
    Bin = list_to_binary(Packet),
    Msg = <<Len:8, Bin/binary>>,
    zlib:compress(Msg).

pack_role([One|Rest], Packet) ->
    #rank_role{
        role_id = RoleId, role_name = RoleName, career = Career, power = Power,  platform = Platform,
        server_num = ServerNum, rank_id = RankId, score = Score, pk_time = PkTime} = One,
    NameBin = pt:write_string(RoleName),
    PlatformBin = pt:write_string(Platform),
    Msg = <<RoleId:64, NameBin/binary, Career:8, Power:32, PlatformBin/binary, ServerNum:16, RankId:16, Score:32, PkTime:32>>,
    pack_role(Rest, [Msg|Packet]);
pack_role(_, Packet) -> Packet.

%% 对玩家数据进行排序
sort_rank_list(List) ->
    F1 = fun(A, B) -> check_up(A, B) end,
    NewList = lists:sort(F1, List),
    F2 = fun(RankRole, {TempList, Value}) ->
            NewRankRole = RankRole#rank_role{rank_id = Value},
            NewTempList = [NewRankRole | TempList],
            {NewTempList, Value + 1}
         end,
    {TmpRankList, _} = lists:foldl(F2, {[], 1}, NewList),
    lists:reverse(TmpRankList).

%% 检测能否上榜，积分>时间
check_up(A, B) ->
    #rank_role{score = ScoreA, pk_time = TimeA} = A,
    #rank_role{score = ScoreB, pk_time = TimeB} = B,
    case ScoreA == ScoreB of
        true -> TimeA < TimeB;
        false -> ScoreA > ScoreB
    end.

%% 刷新玩家排行
refresh_rank(RankList, RankRole) ->
    RoleId = RankRole#rank_role.role_id,
    OldRole = lists:keyfind(RoleId, #rank_role.role_id, RankList),
    case {OldRole, length(RankList) < ?TOP_PK_KV_RANK_SIZE} of
        %% 之前没有上榜
        {false, true} -> sort_rank_list([RankRole | RankList]);
        {false, false} ->
            OldOne = lists:last(RankList),
            OldOneId = OldOne#rank_role.role_id,
            case check_up(RankRole, OldOne) of
                true -> sort_rank_list(lists:keyreplace(OldOneId, #rank_role.role_id, RankList, RankRole));
                false -> RankList
            end;
        {_OldRole, _} -> sort_rank_list(lists:keyreplace(RoleId, #rank_role.role_id, RankList, RankRole))
    end.

%% 更新排行榜玩家信息
update_rank_role(RoleId, KeyValueList, RankList) ->
    case lists:keyfind(RoleId, #rank_role.role_id, RankList) of
        #rank_role{} = RankRole ->
            NewRole = do_update_rank_role(KeyValueList, RankRole),
            {true, NewRole, lists:keyreplace(RoleId, #rank_role.role_id, RankList, NewRole)};
        _ ->
            {false, [], RankList}
    end.

do_update_rank_role([], RankRole) -> RankRole;
do_update_rank_role([{Key, Value}|T], RankRole) ->
    NewRankRole = case Key of
        role_name -> RankRole#rank_role{role_name = Value};
        career -> RankRole#rank_role{career = Value};
        _ -> RankRole
    end,
    do_update_rank_role(T, NewRankRole).

%% ------------------------------- db 处理部分 --------------------------------
db_select_player_top_pk(RoleId) ->
    Sql = io_lib:format(?SQL_SELECT_PLAYER_TOP_PK, [RoleId]),
    case db:get_row(Sql) of
        [Score, GradeRewardList, MatchRewardList, PkTime, EnterCount, ContinuedFail, ContinuedWin] ->
            GradeRewardList2 = util:bitstring_to_term(GradeRewardList),
            MatchRewardList2 = util:bitstring_to_term(MatchRewardList),
            #top_pk_status{score = Score, grade_reward_list = GradeRewardList2,  match_reward_list = MatchRewardList2,
            pk_time = PkTime, enter_count = EnterCount, continued_fail = ContinuedFail, continued_win = ContinuedWin};
        [] -> []
    end.

db_replace_into_player_top_pk(RoleId, TopPkStatus) ->
    #top_pk_status{score = Score, grade_reward_list = GradeRewardList, match_reward_list = MatchRewardList,
        pk_time = PkTime, enter_count = EnterCount, continued_fail = ContinuedFail, continued_win = ContinuedWin} = TopPkStatus,
    GradeRewardListB = util:term_to_bitstring(GradeRewardList),
    MatchRewardListB = util:term_to_bitstring(MatchRewardList),
    Sql = io_lib:format(?SQL_REPLACE_INTO_PLAYER_TOP_PK,
                [RoleId, Score, GradeRewardListB, MatchRewardListB, PkTime, EnterCount, ContinuedFail, ContinuedWin]),
    db:execute(Sql).

db_select_player_top_pk_for_rank() ->
    Sql = io_lib:format(?SQL_SELECT_PLAYER_TOP_PK_FOR_RANK, [round(?TOP_PK_KV_RANK_SIZE*1.5)]),
    db:get_all(Sql).

db_truncate_player_top_pk() ->
    Sql = io_lib:format(?SQL_TRUNCATE_PLAYER_TOP_PK, []),
    db:execute(Sql).

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

db_truncate_rank_center() ->
    Sql = io_lib:format(?SQL_TRUNCATE_RANK_CENTER, []),
    db:execute(Sql).

%% 排行榜数据持久化
db_save_rank_center([]) -> ignore;
db_save_rank_center(RankList) ->
    SqlList = join_data(RankList, 1, ?TOP_PK_KV_RANK_SIZE, []),
    Sql = string:join(SqlList, ", "),
    FormatSql = io_lib:format(?SQL_REPLACE_INTO_RANK_CENTER, [Sql]),
    db:execute(FormatSql).

join_data([One|Rest], Rank, RankMax, Sql) when Rank =<RankMax ->
    #rank_role{
        role_id = RoleId, role_name = RoleName, career = Career, power = Power, platform = Platform,
        server_num = ServerNum, server_id = ServerId, score = Score, pk_time = PkTime} = One,
    Data = io_lib:format("(~p, '~ts', ~p, ~p, '~ts', ~p, ~p, ~p, ~p)",
        [RoleId, RoleName, Career, Power, Platform, ServerNum, ServerId, Score, PkTime]),
    join_data(Rest, Rank+1, RankMax, [Data|Sql]);
join_data(_, _, _RankMax, Sql) -> Sql.


