%% ---------------------------------------------------------------------------
%% @doc 巅峰竞技本服管理进程
%% @author hek
%% @since  2016-11-14
%% @deprecated
%% ---------------------------------------------------------------------------
-module(lib_top_pk_local_mod).
-include("role.hrl").
-include("common.hrl").
-include("server_kv.hrl").
-include("top_pk.hrl").
-include("figure.hrl").
-include("predefine.hrl").
-include("errcode.hrl").
-include("def_fun.hrl").
-include("def_module.hrl").
-include("def_gen_server.hrl").
-export([
    init/0,                     %% 本服进程初始化
    sync_rank_info/2,           %% 系统启动同步排行榜
    daily_update/2,             %% 凌晨更新
    start_local_new_season/2,   %% 单服开启新赛季
    send_local_rank_reward/4,   %% 发放赛季排名奖励
    advance/1,                  %% 活动预告
    act_start/2,                %% 开启活动
    local_sync_act_status/2,    %% 本地同步活动状态到单服进程
    center_sync_act_status/2,   %% 跨服同步活动状态到单服
    enter_match/4,              %% 匹配
    get_rank_info/4,            %% 获取排行榜
    refresh_rank/2,             %% 刷新排行榜
    update_role/3,              %% 更新排行玩家信息
    gm_start/2,                 %% GM开启活动
    gm_end/1,                   %% GM关闭活动
    gm_season_end/1             %% GM结束赛季
]).

%% ---------------------------------------------------------------------------
%% @doc 本服进程初始化
-spec init() -> {ok, State} when
    State          :: #local_state{}.
%% ---------------------------------------------------------------------------
init() ->
    RankList = init_rank_list(),
    SeasonId = lib_server_kv:get_value(?SERVER_KV_TOP_PK_SEASON_ID, 0),
    SeasonWorldLv = lib_top_pk_util:get_season_world_lv(),
    ClsType = lib_server_kv:get_value(?SERVER_KV_TOP_PK_CLS_TYPE, ?ACT_CLS_LOCAL),
    State = #local_state{season_id = SeasonId, world_lv = SeasonWorldLv, cls_type = ClsType, rank_list = RankList},
    mod_top_pk_local:apply_cast({'daily_update', init}),
    %% 进程启动，请求同步一次排行榜数据
    ?IF(ClsType == ?ACT_CLS_CENTER,
            clusters_node:apply_cast(mod_top_pk_rank_center, apply_cast, [{'sync_rank_info', node()}]), skip),
    {ok, State}.

init_rank_list() ->
    List = lib_top_pk_util:db_select_player_top_pk_for_rank(),
    RoleList = [make_record(rank_role, T) || T <- List],
    RankList = lib_top_pk_util:sort_rank_list(RoleList),
    LastRankList = lists:sublist(RankList, ?TOP_PK_KV_RANK_SIZE),
    Platform = config:get_platform(),
    ServerNum = config:get_server_num(),
    ServerId = config:get_server_id(),
    F = fun(#rank_role{role_id = RoleId} = RankRole) ->
        Figure = lib_role:get_role_elem(RoleId, #ets_role_show.figure, #figure{}),
        CombatPower = lib_role:get_role_elem(RoleId, #ets_role_show.combat_power, 0),
        RankRole#rank_role{
            role_name = Figure#figure.name, career = Figure#figure.career,
            power = CombatPower, platform = Platform, server_num = ServerNum, server_id = ServerId}
    end,
    lists:map(F, LastRankList).

make_record(rank_role, [RoleId, Score, PkTime]) ->
    #rank_role{role_id = RoleId, score = Score, pk_time = PkTime}.

%% ---------------------------------------------------------------------------
%% @doc 系统启动同步排行榜
-spec sync_rank_info(State, Msg) -> {ok, NewState} when
    State           :: #local_state{},
    Msg             :: binary(),
    NewState        :: #local_state{}.
%% ---------------------------------------------------------------------------
sync_rank_info(#local_state{cls_type = ?ACT_CLS_CENTER} = State, Msg) ->
    RankList = lib_top_pk_util:unpacket_role_rank(Msg),
    {ok, State#local_state{rank_list = RankList}};
sync_rank_info(State, _Msg) ->
    {ok, State}.

%% ---------------------------------------------------------------------------
%% @doc 凌晨更新
-spec daily_update(State, FromSource) -> {ok, NewState} when
    State           :: #local_state{},
    FromSource      :: atom(),          %% 调用入口：默认none, 进程初始化为init
    NewState        :: #local_state{}.
%% ---------------------------------------------------------------------------
daily_update(State, _FromSource) ->
    #local_state{season_id = SeasonId, cls_type = ClsType} = State,
    CurSeasonId = lib_top_pk_util:get_cur_season_id(),
    if
        %% 单服竞技环境单服触发开启新赛季
        SeasonId =/= CurSeasonId andalso ClsType == ?ACT_CLS_LOCAL -> start_new_season(State, CurSeasonId);
        %% 跨服竞技环境，当跨服中心赛季结算的时候，单服节点关闭了
        %% 这时单服进程init的时候触发开启新赛季
        %% SeasonId =/= CurSeasonId andalso FromSource=:=init -> start_new_season(State, CurSeasonId);
        %% 跨服竞技环境由跨服统一触发新赛季
        SeasonId =/= CurSeasonId -> {ok, State};
        true -> {ok, State}
    end.

%% 本服开启新赛季
start_new_season(State, CurSeasonId) ->
    NowTime = utime:unixtime(),
    WorldLv = util:get_world_lv(),
    SettleNum = lib_top_pk_util:get_season_settle_num(),
    #local_state{
        season_id = OldSeasonId, world_lv = OldWorldLv, cls_type = ClsType, rank_list = RankList} = State,
    NewSettleNum = ?IF(OldSeasonId == 0, 0, SettleNum+1),
    SeasonServerKv = #server_kv{key = ?SERVER_KV_TOP_PK_SEASON_ID, value = CurSeasonId, time = NowTime},
    WorldLvServerKv = #server_kv{key = ?SERVER_KV_TOP_PK_WORLD_LV, value = WorldLv, time = NowTime},
    SettleServerKv = #server_kv{key = ?SERVER_KV_TOP_PK_SEASON_SETTLE_NUM, value = NewSettleNum, time = NowTime},
    %% 清理上一个赛季玩家数据、初始化新赛季信息
    F = fun() ->
        lib_top_pk_util:db_truncate_player_top_pk(),
        lib_server_kv:update_server_kv_db(SeasonServerKv),
        lib_server_kv:update_server_kv_db(WorldLvServerKv),
        lib_server_kv:update_server_kv_db(SettleServerKv),
        ok
    end,
    NewState = case db:transaction(F) of
        ok ->
            lib_server_kv:update_server_kv_ets(SeasonServerKv),
            lib_server_kv:update_server_kv_ets(WorldLvServerKv),
            lib_server_kv:update_server_kv_ets(SettleServerKv),
            State#local_state{season_id = CurSeasonId, world_lv = WorldLv, rank_list = []};
        Err -> ?ERR("error:~p~n", [Err]), State
    end,
    %% 通知在线玩家新赛季信息
    util:cast_event_to_players({'apply_cast', ?APPLY_CAST_SAVE, lib_top_pk, start_new_season, [CurSeasonId]}),

    %% 发放上一个赛季排名奖励(前10名)
    case ClsType of
        ?ACT_CLS_LOCAL ->
            SortRankList = lib_top_pk_util:sort_rank_list(RankList),
            AwardRankList = lists:sublist(SortRankList, ?TOP_PK_KV_SEASON_RANK_AWARD_NUM),
            send_season_rank_reward(AwardRankList, OldSeasonId, OldWorldLv);
        _ -> skip
    end,
    ?INFO("local start_new_season:~p~n", [NowTime]),
    {ok, NewState}.

send_season_rank_reward(RankList, OldSeasonId, OldWorldLv) ->
    case util:get_open_day()>=?TOP_PK_KV_SEASON_AWARD_NEED_OPENDAY of
        true -> spawn(fun() -> do_send(RankList, OldSeasonId, OldWorldLv, 1) end);
        false -> skip
    end.

do_send([], _OldSeasonId, _OldWorldLv, _Index) -> ok;
do_send([One | Rest], OldSeasonId, OldWorldLv, Index) ->
    case Index rem 10 == 0 of
        true  -> timer:sleep(50);
        false -> skip
    end,
    #rank_role{role_id = RoleId, rank_id = RankId, score = Score} = One,
    InitGradeInfo = data_top_pk:get_grade_info(Score),
    GradeInfo = ?IF(InitGradeInfo =/= [], InitGradeInfo, #base_top_pk_grade_info{}),
    Title = utext:get(2810001),
    Content = utext:get(2810002, [GradeInfo#base_top_pk_grade_info.name, RankId]),
    RewardList = data_top_pk:get_rank_reward(OldWorldLv, RankId),
    lib_mail_api:send_sys_mail([RoleId], ?MOD_TOPPK, Title, Content, RewardList),
    do_send(Rest, OldSeasonId, OldWorldLv, Index+1).

%% 单服开启新赛季
start_local_new_season(State, CurSeasonId) ->
    #local_state{cls_type = ClsType} = State,
    {ok, NewState} = case ClsType of
        ?ACT_CLS_CENTER -> start_new_season(State, CurSeasonId);
        _ -> {ok, State}
    end,
    {ok, NewState}.

%% 发放单服赛季排名奖励
send_local_rank_reward(State, RoleId, RankId, Score) ->
    case util:get_open_day()>=?TOP_PK_KV_SEASON_AWARD_NEED_OPENDAY of
        true ->
            #local_state{world_lv = WorldLv} = State,
            InitGradeInfo = data_top_pk:get_grade_info(Score),
            GradeInfo = ?IF(InitGradeInfo =/= [], InitGradeInfo, #base_top_pk_grade_info{}),
            Title = utext:get(2810003),
            Content = utext:get(2810004, [GradeInfo#base_top_pk_grade_info.name, RankId]),
            RewardList = data_top_pk:get_rank_reward(WorldLv, RankId),
            lib_mail_api:send_sys_mail([RoleId], ?MOD_TOPPK, Title, Content, RewardList);
        false -> skip
    end,
    ok.

%% ---------------------------------------------------------------------------
%% @doc 活动预告
-spec advance(State) -> {ok, NewState} when
    State          :: #local_state{},
    NewState       :: #local_state{}.
%% ---------------------------------------------------------------------------
advance(State) ->
    %% 确认本场比赛的竞技环境
    ClsType = get_cls_type(),
    OldClsType = State#local_state.cls_type,
    AdvanceTime = data_activitycalen_m:get_advance(?MOD_TOPPK, 0),
    case ClsType of
        ?ACT_CLS_LOCAL -> lib_chat:send_TV({all}, ?MOD_TOPPK, 3, [AdvanceTime]);
        ?ACT_CLS_CENTER -> lib_chat:send_TV({all}, ?MOD_TOPPK, 4, [AdvanceTime])
    end,
    ServerKv = #server_kv{key = ?SERVER_KV_TOP_PK_CLS_TYPE, value = ClsType, time = utime:unixtime()},
    lib_server_kv:update_server_kv(ServerKv),
    %% 开启跨服环境，将排行数据上传到跨服
    case {ClsType, OldClsType} of
        {?ACT_CLS_CENTER, ?ACT_CLS_LOCAL} ->
            Packet = lib_top_pk_util:pack_role_rank(State#local_state.rank_list),
            clusters_node:apply_cast(mod_top_pk_rank_center, apply_cast, [{'upload_rank_to_center', Packet}]);
        _ -> skip
    end,
    {ok, State#local_state{cls_type = ClsType}}.

%% 获取竞技环境类型
get_cls_type() ->
    %% 满足开服天数、世界等级、结算次数时开启跨服环境
    SettleNum = lib_top_pk_util:get_season_settle_num(),
    case util:get_open_day()>=?TOP_PK_KV_START_CENTER_OPEN_DAY andalso
        util:get_world_lv()>=?TOP_PK_KV_START_CENTER_WORLD_LV andalso SettleNum>0 of
        true -> ?ACT_CLS_CENTER;
        false -> ?ACT_CLS_LOCAL
    end.

%% 开启活动
act_start(State, Args) ->
    ClsType = State#local_state.cls_type,
    case ClsType of
        ?ACT_CLS_LOCAL -> mod_top_pk_match:act_start(Args);
        _ -> clusters_node:apply_cast(mod_top_pk_match, act_start, [Args])
    end,
    ok.

%% 本地同步活动状态到单服进程
local_sync_act_status(State, Status) ->
    case Status of
        ?ACT_STATUS_START ->
            lib_activitycalen_api:success_start_activity(?MOD_TOPPK),
            lib_chat:send_TV({all}, ?MOD_TOPPK, 1, []);
        ?ACT_STATUS_STOP ->
            lib_activitycalen_api:success_end_activity(?MOD_TOPPK),
            lib_chat:send_TV({all}, ?MOD_TOPPK, 2, []);
        _ -> skip
    end,
    {ok, State#local_state{act_status = Status}}.

%% 跨服同步活动状态到单服
center_sync_act_status(#local_state{cls_type = ?ACT_CLS_CENTER} = State, Status) ->
    case Status of
        ?ACT_STATUS_START ->
            lib_activitycalen_api:success_start_activity(?MOD_TOPPK),
            lib_chat:send_TV({all}, ?MOD_TOPPK, 13, []);
        ?ACT_STATUS_STOP ->
            lib_activitycalen_api:success_end_activity(?MOD_TOPPK),
            lib_chat:send_TV({all}, ?MOD_TOPPK, 14, []);
        _ -> skip
    end,
    {ok, State#local_state{act_status = Status}};
center_sync_act_status(State, _Status) ->
    {ok, State}.

%% 匹配
enter_match(State, Node, RoleId, Args) ->
    ClsType = State#local_state.cls_type,
    case ClsType of
        ?ACT_CLS_LOCAL -> mod_top_pk_match:enter_match(Node, RoleId, Args);
        _ -> clusters_node:apply_cast(mod_top_pk_match, enter_match, [Node, RoleId, Args])
    end.

%% ---------------------------------------------------------------------------
%% @doc 获取排行榜
-spec get_rank_info(State, PlayerId, Page, PageSize) -> ok when
    State          :: #local_state{},
    PlayerId       :: integer(),
    Page           :: integer(),
    PageSize       :: integer().
%% ---------------------------------------------------------------------------
get_rank_info(State, PlayerId, Page, PageSize) ->
    #local_state{act_status = ActStatus, cls_type = ClsType} = State,
    case {ActStatus, ClsType} of
        {?ACT_STATUS_START, ?ACT_CLS_CENTER} ->
            clusters_node:apply_cast(mod_top_pk_rank_center, apply_cast, [{'get_rank_info', node(), PlayerId, Page, PageSize}]);
        _ -> send_rank_info(State, PlayerId, Page, PageSize)
    end.

send_rank_info(State, PlayerId, Page, PageSize) ->
    #local_state{rank_list = RankList, cls_type = ClsType} = State,
    Length = erlang:length(RankList),
    PageNums = (Length div PageSize) + 1,
    case Page > PageNums of
        true -> SubRankList = RankList;
        false ->
            Pos = (Page - 1)*PageSize +1,
            SubRankList = lists:sublist(RankList, Pos, PageSize)
    end,
    case lists:keyfind(PlayerId, #rank_role.role_id, RankList) of
        #rank_role{rank_id = MyRankId} -> skip;
        _ -> MyRankId = 0
    end,
    ListData = [{RankId, RoleId, RoleName, Career, Power, Platform, ServerNum, Score} ||
        #rank_role{
            rank_id = RankId, role_id = RoleId, role_name = RoleName, career = Career,
            power = Power, platform = Platform, server_num = ServerNum, score = Score} <- SubRankList],
    {ok, Bin} = pt_281:write(28115, [Page, PageSize, Length, ClsType, ListData, MyRankId]),
    lib_server_send:send_to_uid(PlayerId, Bin),
    ok.

%% ---------------------------------------------------------------------------
%% @doc 刷新排行榜
-spec refresh_rank(State, RankRole) -> {ok, NewState} when
    State          :: #local_state{},
    RankRole       :: #rank_role{},
    NewState       :: #local_state{}.
%% ---------------------------------------------------------------------------
refresh_rank(State, RankRole) ->
    #local_state{cls_type = ClsType, rank_list = RankList} = State,
    NewRankList = case ClsType of
        ?ACT_CLS_CENTER ->
            clusters_node:apply_cast(mod_top_pk_rank_center, apply_cast, [{'refresh_rank', RankRole}]),
            RankList;
        _ -> lib_top_pk_util:refresh_rank(RankList, RankRole)
    end,
    {ok, State#local_state{rank_list = NewRankList}}.

%% ---------------------------------------------------------------------------
%% @doc 更新排行玩家信息
-spec update_role(State, RoleId, KeyValueList) -> {ok, NewState} when
    State          :: #local_state{},
    RoleId         :: integer(),
    KeyValueList   :: [{Key::atom(), Value::term()}],
    NewState       :: #local_state{}.
%% ---------------------------------------------------------------------------
update_role(State, RoleId, KeyValueList) ->
    #local_state{cls_type = ClsType, rank_list = RankList} = State,
    case ClsType of
        ?ACT_CLS_CENTER ->
            NewRankList = RankList,
            clusters_node:apply_cast(mod_top_pk_rank_center, apply_cast, [{'update_role', RoleId, KeyValueList}]);
        _ -> {_Flag, _NewRole, NewRankList} = lib_top_pk_util:update_rank_role(RoleId, KeyValueList, RankList)
    end,
    {ok, State#local_state{rank_list = NewRankList}}.

%% GM开启活动
gm_start(State, Time) ->
    %% 活动预告
    {ok, NewState} = advance(State),
    %% 开启活动
    case NewState#local_state.cls_type of
        ?ACT_CLS_LOCAL -> mod_top_pk_match:gm_start(Time);
        _ -> clusters_node:apply_cast(mod_top_pk_match, gm_start, [Time])
    end,
    {ok, NewState}.

%% GM关闭活动
gm_end(State) ->
    ClsType = State#local_state.cls_type,
    ActStatus = State#local_state.act_status,
    %% 开启活动
    case {ActStatus, ClsType} of
        {?ACT_STATUS_START, ?ACT_CLS_LOCAL} -> mod_top_pk_match:gm_end();
        {?ACT_STATUS_START, ?ACT_CLS_CENTER} ->
            clusters_node:apply_cast(mod_top_pk_match, gm_end, []);
        _ -> skip
    end,
    {ok, State}.

%% GM结束赛季
gm_season_end(State) ->
    ClsType = State#local_state.cls_type,
    ActStatus = State#local_state.act_status,
    CurSeasonId = lib_top_pk_util:get_cur_season_id(),
    case {ActStatus, ClsType} of
        {?ACT_STATUS_STOP, ?ACT_CLS_LOCAL} -> {ok, NewState} = start_new_season(State, CurSeasonId);
        {?ACT_STATUS_STOP, ?ACT_CLS_CENTER} ->
            clusters_node:apply_cast(mod_top_pk_rank_center, apply_cast, [{'gm_season_end'}]), NewState = State;
        _ -> NewState = State
    end,
    {ok, NewState}.
