%%%-----------------------------------
%%% @Module  : mod_kf_1vn_local
%%% @Email   : ming_up@foxmail.com
%%% @Created : 2018.1.24
%%% @Description: 跨服1vN(本地)
%%%-----------------------------------
-module(mod_kf_1vn_local).

-include("common.hrl").
-include("def_module.hrl").
-include("kf_1vn.hrl").
-include("predefine.hrl").
-include("shop.hrl").
-include("errcode.hrl").

%% API
-export([start_link/0, sign/6, sign_back/1, sign_info/1, get_act_info/2, enter/1, stage_change/5,
        quit/3, get_score_rank/3, get_def_rank/2, get_challenge_rank/2, get_rank/3, set_race_1_rank/1,
        update_race_2_rank/3, change_def_num_m/1, sync_state/1, set_sign_num/1,
        update_sign_power/2, reconnect/1, send_to_area/2, shop_check/3
        % , get_def_daily_award/1
    ]).
-export([gm_start_1/3, gm_start_2/2, gm_next_stage/0]).
-export([get_auction_stage/1, sync_auction_state/1]).

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

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

get_act_info(Id, Sid) ->
    gen_server:cast(?MODULE, {get_act_info, Id, Sid}).

sign(ServerId, Id, Lv, Name, CombatPower, ServerName) ->
    gen_server:cast(?MODULE, {sign, ServerId, Id, Lv, Name, CombatPower, ServerName}).

sign_back(Id) ->
    gen_server:cast(?MODULE, {sign_back, Id}).

sign_info(SignInfos) ->
    gen_server:cast(?MODULE, {sign_info, SignInfos}).

enter(KfRole) ->
    gen_server:cast(?MODULE, {enter, KfRole}).

stage_change(Stage, MatchTurn, EdTime, SubStage, SubEdTime) ->
    gen_server:cast(?MODULE, {stage_change, Stage, MatchTurn, EdTime, SubStage, SubEdTime}).

quit(Id, CopyId, QuitType) ->
    gen_server:cast(?MODULE, {quit, Id, CopyId, QuitType}).

reconnect(Id) ->
    gen_server:cast(?MODULE, {reconnect, Id}).

get_score_rank(Id, Sid, CArea) ->
    gen_server:cast(?MODULE, {get_score_rank, Id, Sid, CArea}).

get_def_rank(Id, Sid) ->
    gen_server:cast(?MODULE, {get_def_rank, Id, Sid}).

get_challenge_rank(Id, Sid) ->
    gen_server:cast(?MODULE, {get_challenge_rank, Id, Sid}).

get_rank(Id, Sid, CArea) ->
    gen_server:cast(?MODULE, {get_rank, Id, Sid, CArea}).

% get_def_daily_award(Id) ->
%     gen_server:cast(?MODULE, {get_def_daily_award, Id}).

set_race_1_rank(ShortRankM) ->
    gen_server:cast(?MODULE, {set_race_1_rank, ShortRankM}).

update_race_2_rank(Area, DefRank, ChallengerRank) ->
    gen_server:cast(?MODULE, {update_race_2_rank, Area, DefRank, ChallengerRank}).

change_def_num_m(DefNumM) ->
    gen_server:cast(?MODULE, {change_def_num_m, DefNumM}).

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

get_auction_stage(Id) ->
    gen_server:cast(?MODULE, {get_auction_stage, Id}).

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

set_sign_num(Num) ->
    gen_server:cast(?MODULE, {set_sign_num, Num}).

gm_start_1(SignTime, Race1PreTime, Race1Time) ->
    gen_server:cast(?MODULE, {gm_start_1, SignTime, Race1PreTime, Race1Time}).

gm_start_2(Race2PreTime, Race2Time) ->
    gen_server:cast(?MODULE, {gm_start_2, Race2PreTime, Race2Time}).

shop_check(RoleId, KeyList, ShopTypeList) ->
    gen_server:cast(?MODULE, {shop_check, RoleId, KeyList, ShopTypeList}).

% gm_end() ->
%     gen_server:cast(?MODULE, {gm_end}).

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

update_sign_power(Id, Power) ->
    gen_server:cast(?MODULE, {update_sign_power, Id, Power}).

send_to_area(Id, BinData) ->
    gen_server:cast(?MODULE, {send_to_area, Id, BinData}).

init([]) ->
    Node = clusters_node:get_node(),
    {ok, #local_state{stage=?KF_1VN_FREE, node=Node}}.

handle_call(Request, _From, State) ->
    case catch do_handle_call(Request, State) of
        {ok, Reply} ->
            {reply, Reply, State};
        Err ->
            ?ERR("Handle request[~p] error:~p~n", [Request, Err]),
            {noreply, State}
    end.

do_handle_call(_Request, _State) ->
    ?ERR("Handle unkown request[~p]~n", [_Request]),
    {ok, ok}.


handle_cast(Msg, State) ->
    case catch do_handle_cast(Msg, State) of
        {noreply, NewState} ->
            {noreply, NewState};
        Err ->
            ?ERR("Handle msg[~p] error:~p~n", [Msg, Err]),
            {noreply, State}
    end.

do_handle_cast({gm_start_1, SignTime, Race1PreTime, Race1Time}, State) ->
    clusters_node:apply_cast(mod_kf_1vn_mgr, gm_start_1, [SignTime, Race1PreTime, Race1Time]),
    {noreply, State};

do_handle_cast({gm_start_2, Race2PreTime, Race2Time}, State) ->
    clusters_node:apply_cast(mod_kf_1vn_mgr, gm_start_2, [Race2PreTime, Race2Time]),
    {noreply, State};

do_handle_cast({gm_end}, State) ->
    clusters_node:apply_cast(mod_kf_1vn_mgr, ac_end, []),
    {noreply, State};

do_handle_cast({gm_next_stage}, State) ->
    Stage = State#local_state.stage,
    NewStage = Stage + 1,
    if
        NewStage >= 6 ->
            clusters_node:apply_cast(mod_kf_1vn, gm_end, []);
        true ->
            clusters_node:apply_cast(mod_kf_1vn_mgr, gm_stage_change, [NewStage])
    end,
    {noreply, State};

%% 同步资格赛的排行榜
do_handle_cast({set_race_1_rank, RankM}, State) ->
    {noreply, State#local_state{race_1_rank_m=RankM}};

%% 同步守擂赛的排行榜
do_handle_cast({update_race_2_rank, Area, DefRank, ChallengerRank}, State) ->
    #local_state{def_rank_m=DefRankM, challenger_rank_m=ChallengerRankM} = State,
    DefRankM1 = DefRankM#{Area => DefRank},
    ChallengerRankM1 = ChallengerRankM#{Area => ChallengerRank},
    {noreply, State#local_state{def_rank_m=DefRankM1, challenger_rank_m=ChallengerRankM1}};

%% 获取积分排行榜
do_handle_cast({get_score_rank, Id, Sid, CArea}, State) ->
    Area = case CArea of
        0 -> get_area(Id, State#local_state.sign_info);
        _ -> CArea
    end,
    Ranks = maps:get(Area, State#local_state.race_1_rank_m, []),
    Ranks1 = [{
        E#kf_1vn_score_rank.rank, E#kf_1vn_score_rank.id, E#kf_1vn_score_rank.server_num, E#kf_1vn_score_rank.name, E#kf_1vn_score_rank.guild_name, E#kf_1vn_score_rank.vip,
        E#kf_1vn_score_rank.score, E#kf_1vn_score_rank.win, E#kf_1vn_score_rank.lose, E#kf_1vn_score_rank.combat_power, E#kf_1vn_score_rank.career} || E <- Ranks],
    {ok, BinData} = pt_621:write(62110, [Area, Ranks1]),
    lib_server_send:send_to_sid(Sid, BinData),
    {noreply, State};

do_handle_cast({get_def_rank, Id, Sid}, State) ->
    Area = get_area(Id, State#local_state.sign_info),
    Ranks = maps:get(Area, State#local_state.def_rank_m, []),
    Ranks1 = [{
        E#kf_1vn_def_rank.rank, E#kf_1vn_def_rank.id, E#kf_1vn_def_rank.server_num, E#kf_1vn_def_rank.name, E#kf_1vn_def_rank.guild_name, E#kf_1vn_def_rank.vip,
        E#kf_1vn_def_rank.score, E#kf_1vn_def_rank.race_2_turn, E#kf_1vn_def_rank.race_2_lose, E#kf_1vn_def_rank.combat_power, E#kf_1vn_def_rank.race_2_time} || E <- Ranks],
    {ok, BinData} = pt_621:write(62114, [Ranks1]),
    lib_server_send:send_to_sid(Sid, BinData),
    {noreply, State};

do_handle_cast({get_challenge_rank, Id, Sid}, State) ->
    Area = get_area(Id, State#local_state.sign_info),
    Ranks = maps:get(Area, State#local_state.challenger_rank_m, []),
    Ranks1 = [{
        E#kf_1vn_challenger_rank.rank, E#kf_1vn_challenger_rank.id, E#kf_1vn_challenger_rank.server_num, E#kf_1vn_challenger_rank.name, E#kf_1vn_challenger_rank.guild_name, E#kf_1vn_challenger_rank.vip,
        E#kf_1vn_challenger_rank.score, E#kf_1vn_challenger_rank.combat_power, E#kf_1vn_challenger_rank.career, E#kf_1vn_challenger_rank.race_2_turn, E#kf_1vn_challenger_rank.result} || E <- Ranks],
    {ok, BinData} = pt_621:write(62115, [Ranks1]),
    lib_server_send:send_to_sid(Sid, BinData),
    {noreply, State};

do_handle_cast({get_rank, Id, Sid, CArea}, State) ->
    Area = case CArea of
        0 -> get_area(Id, State#local_state.sign_info);
        _ -> CArea
    end,
    Ranks = maps:get(Area, State#local_state.def_rank_m, []),
    Ranks1 = [{
        E#kf_1vn_def_rank.rank, E#kf_1vn_def_rank.server_id, E#kf_1vn_def_rank.id, E#kf_1vn_def_rank.server_num, E#kf_1vn_def_rank.name, E#kf_1vn_def_rank.guild_name, E#kf_1vn_def_rank.vip,
        E#kf_1vn_def_rank.score, E#kf_1vn_def_rank.race_2_turn, E#kf_1vn_def_rank.combat_power, E#kf_1vn_def_rank.career, E#kf_1vn_def_rank.race_2_time, E#kf_1vn_def_rank.race_2_lose} || E <- Ranks],
    {ok, BinData} = pt_621:write(62116, [Area, Ranks1, []]),
    lib_server_send:send_to_sid(Sid, BinData),
    {noreply, State};

% do_handle_cast({get_def_daily_award, Id}, State) ->
%     case lists:keyfind(Id, 1, State#state.sign_info) of
%         false -> skip;
%         {_, Area} ->
%             Ranks = maps:get(Area, State#state.def_rank_m, []),
%             case lists:keyfind(Id, #kf_1vn_def_rank.id, Ranks) of
%                 false -> skip;
%                 #kf_1vn_def_rank{rank=Rank} -> skip
%             end
%     end,
%     {noreply, State};

do_handle_cast({get_act_info, Id, Sid}, State) ->
    #local_state{sign_num=SignNum, def_num_m=DefNumM, sign_info=SignInfo} = State,
    IsSign = case lists:keyfind(Id, 1, SignInfo) of
        false -> Area=0, 0;
        {_, Area} -> 1
    end,
    DefNum = maps:get(Area, DefNumM, 0),
    {ok, BinData} = pt_621:write(62100, [IsSign, SignNum, DefNum, Area]),
    lib_server_send:send_to_sid(Sid, BinData),
    {noreply, State};

do_handle_cast({sign, ServerId, Id, Lv, Name, CombatPower, SerName}, State) ->
   case State#local_state.stage of
       ?KF_1VN_SIGN ->
           clusters_node:apply_cast(mod_kf_1vn, sign, [State#local_state.node, ServerId, Id, Lv, Name, CombatPower, SerName]);
       _ -> skip
   end,
    {noreply, State};

%% 更新报名玩家的战力
do_handle_cast({update_sign_power, Id, Power}, State) ->
    case State#local_state.stage of
        ?KF_1VN_FREE -> skip;
        ?KF_1VN_END -> skip;
        ?KF_1VN_SIGN ->
            case lists:keyfind(Id, 1, State#local_state.sign_info) of
                false -> skip;
                _ -> clusters_node:apply_cast(mod_kf_1vn, update_sign_info, [Id, [{power, Power}]])
            end;
        _ ->
            case lists:keyfind(Id, 1, State#local_state.sign_info) of
                {Id, Area} -> clusters_node:apply_cast(mod_kf_1vn, update_role, [Area, Id, [{power, Power}]]);
                _ -> skip
            end
    end,
    {noreply, State};

%% 报名返回
do_handle_cast({sign_back, Id}, State) ->
    #local_state{sign_info=SignInfo} = State,
    lib_kf_1vn:db_save_sign(Id),
    {noreply, State#local_state{sign_info=[{Id, 0}|lists:keydelete(Id, 1, SignInfo)]}};

%% 同步报名人数
do_handle_cast({set_sign_num, Num}, State) ->
    % #state{sign_num=SignNum} = State,
    {noreply, State#local_state{sign_num=Num}};

%% 同步报名信息
do_handle_cast({sign_info, SignInfos}, State) ->
    {noreply, State#local_state{sign_info=SignInfos}};

%% 进入场景
do_handle_cast({enter, KfRole}, State) ->
    case State#local_state.stage >= ?KF_1VN_RACE_1_PRE of
        true  -> clusters_node:apply_cast(mod_kf_1vn, enter, [State#local_state.node, KfRole]);
        false -> skip
    end,
    {noreply, State};

%% 阶段变换（跨服中心派发）
do_handle_cast({stage_change, Stage, MatchTurn, EdTime, SubStage, SubEdTime}, State) ->
    OpenDayLimit = data_kf_1vn_m:get_config(open_day),
    case util:get_open_day() >= OpenDayLimit of
        false -> {noreply, State};
        true  ->
            {ok, BinData} =  pt_621:write(62101, [Stage, MatchTurn, EdTime, SubStage, SubEdTime]),
            lib_server_send:send_to_all(BinData),
            Node = clusters_node:get_node(),
            case Stage of
                ?KF_1VN_SIGN -> %% 请求一下竞拍数据
                    clusters_node:apply_cast(mod_kf_1vn_auction, sync_auction_state, [Node, 1]);
                ?KF_1VN_RACE_1_PRE ->
                    OpenLv = data_kf_1vn:get_value(?KF_1VN_CFG_ENTER_LV),
                    lib_chat:send_TV({all_lv, {OpenLv, 1000}}, ?MOD_KF_1VN, 1, []),
                    lib_activitycalen_api:success_start_activity(?MOD_KF_1VN);
                ?KF_1VN_FREE ->
                    lib_activitycalen_api:success_end_activity(?MOD_KF_1VN);
                ?KF_1VN_END ->
                    clusters_node:apply_cast(mod_kf_1vn_auction, sync_auction_state, [Node, 1]);
                _ -> skip
            end,
            case Stage of
                ?KF_1VN_SIGN ->
                    lib_kf_1vn:clean_1vn(),
                    SignList = lib_kf_1vn:get_sign_list(), %% 获取报名列表
                    %% 报名结束前5分钟传闻提示
                    SendTime = max(EdTime - utime:unixtime() - 5 * 60, 0),
                    erlang:send_after(SendTime * 1000, self(), borad_sign),
                    {noreply, #local_state{stage=Stage, sub_stage=SubStage, edtime=EdTime, sign_info=SignList, node=Node}};
                ?KF_1VN_FREE ->
                    lib_kf_1vn:db_clean_sign(),
                    {noreply, State#local_state{stage=Stage, sub_stage=SubStage, edtime=EdTime, sign_num=0, def_num_m=#{}, sign_info=[]}};
                _ ->
                    {noreply, State#local_state{stage=Stage, sub_stage=SubStage, edtime=EdTime}}
            end
    end;

do_handle_cast({change_def_num_m, DefNumM}, State) ->
    {noreply, State#local_state{def_num_m=DefNumM}};

do_handle_cast({quit, Id, CopyId, QuitType}, State) ->
    clusters_node:apply_cast(mod_kf_1vn, quit, [State#local_state.node, Id, CopyId, QuitType]),
    {noreply, State};

do_handle_cast({reconnect, Id}, State) ->
    #local_state{stage = Stage} = State,
    if
        Stage =:= ?KF_1VN_FREE orelse Stage =:= ?KF_1VN_SIGN orelse Stage =:= ?KF_1VN_END ->
            lib_scene:player_change_default_scene(Id, [{group, 0}, {ghost, 0}, {action_free, ?ERRCODE(err621_in_kf_1vn)}]);
        true ->
            skip
    end,
    {noreply, State};

do_handle_cast({sync_state, [Stage, SubStage, OpTime, EdTime, SignNum, DefNumM, DefRankM]}, State) ->
    OpenDayLimit = data_kf_1vn_m:get_config(open_day),
    case util:get_open_day() >= OpenDayLimit of
        false -> {noreply, State#local_state{def_rank_m=DefRankM}};
        true  ->
            NewState = State#local_state{stage=Stage, sub_stage=SubStage, optime=OpTime, edtime=EdTime, sign_num=SignNum, def_num_m=DefNumM, def_rank_m=DefRankM},
            {noreply, NewState}
    end;

do_handle_cast({get_auction_stage, Id}, State) ->
    #local_state{auction_stage=Stage, auction_edtime=EdTime} = State,
    {ok, BinData} = pt_621:write(62129, [Stage, EdTime]),
    lib_server_send:send_to_uid(Id, BinData),
    {noreply, State};

do_handle_cast({sync_auction_state, [Stage, EdTime, Broadcast]}, State) ->
    OpenDayLimit = data_kf_1vn_m:get_config(open_day),
    case util:get_open_day() >= OpenDayLimit of
        true ->
            case Broadcast of
                1 ->
                    {ok, BinData} = pt_621:write(62129, [Stage, EdTime]),
                    lib_server_send:send_to_all(BinData);
                _ -> skip
            end,
            {noreply,State#local_state{auction_stage=Stage, auction_edtime=EdTime}};
        _ ->
            {noreply, State}
    end;

do_handle_cast({send_to_area, Id, BinData}, State) ->
    #local_state{sign_info = SignL} = State,
    case lists:keyfind(Id, 1, SignL) of
        {Id, Area} ->
            clusters_node:apply_cast(mod_kf_1vn, send_to_area, [Area, BinData]);
        _ -> skip
    end,
    {noreply, State};

%% 商店开启检测
do_handle_cast({shop_check, RoleId, KeyList, ShopTypeList}, State) ->
    #local_state{auction_stage=Stage} = State,
    if
        Stage == 1 -> %% 商城开启中，跳回玩家进程做其他商城检测
            lib_player:apply_cast(RoleId, ?APPLY_CAST_STATUS, lib_shop, shop_type_check, [KeyList, lists:delete(?SHOP_1VN, lists:delete(?SHOP_1VN_DEF, ShopTypeList))]);
        true ->
            lib_server_send:send_to_uid(RoleId, pt_153, 15302, [?ERRCODE(err621_shop_not_open), KeyList])
    end,
    {noreply, State};

do_handle_cast(_Msg, State) ->
    ?ERR("Handle unkown msg[~p]~n", [_Msg]),
    {noreply, State}.

handle_info(Info, State) ->
    case catch do_handle_info(Info, State) of
        {noreply, NewState} ->
            {noreply, NewState};
        Err ->
            ?ERR("Handle info[~p] error:~p~n", [Info, Err]),
            {noreply, State}
    end.

do_handle_info(borad_sign, State) ->
    OpenLv = data_kf_1vn:get_value(?KF_1VN_CFG_ENTER_LV),
    lib_chat:send_TV({all_lv, {OpenLv, 1000}}, ?MOD_KF_1VN, 5, []),
    {noreply, State};

do_handle_info(_Info, State) ->
    ?ERR("Handle unkown info[~p]~n", [_Info]),
    {noreply, State}.

terminate(_Reason, _State) ->
    ok.

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

get_area(RoleId, SignInfo) ->
    case lists:keyfind(RoleId, 1, SignInfo) of
        false -> 1;
        {_, 0} -> 1;
        {_, TmpArea} -> TmpArea
    end.
