%%%-------------------------------------------------------------------
%%% @author ljy
%%% @doc
%%%     跨服聊天分区管理
%%% @end
%%% Created : 15. 9月 2020 20:08
%%%-------------------------------------------------------------------
-module(mod_chat_zone).

-behaviour(gen_server).

-include("common.hrl").
-include("common_rank.hrl").
-include("def_fun.hrl").


-export([start_link/0, zone_chat/2, country_chat/2, recalc_zone/1, add_svrs/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, [], []).

%% 跨服分区聊天
zone_chat(ServerId, BinData) ->
    gen_server:cast(?MODULE, {zone_chat, ServerId, BinData}).

%% 本国聊天
country_chat(ServerId, BinData) ->
    gen_server:cast(?MODULE, {country_chat, ServerId, BinData}).

%% 重新分区后
recalc_zone(CBMap) ->
    gen_server:cast(?MODULE, {recalc_zone, CBMap}).

%% 添加注册服
add_svrs(CBMap) ->
    gen_server:cast(?MODULE, {add_svrs, CBMap}).

init(_Args) ->
    SrvZoneMap = czone:get_svr_zone_map(),
    SvrFactMap = czone:get_faction_map(svr_faction_map),
    ZoneIds = cross_zone:get_all_zone_ids(czone),
    ZoneInfo = [begin
                    SrvList = cross_zone:get_zone_servers(czone, ZoneId),
                    {ZoneId, SrvList}
                end || ZoneId <- ZoneIds],
    {ok, {SrvZoneMap, ZoneInfo, SvrFactMap}}.

handle_call(Request, From, State) ->
    try
        do_handle_call(Request, From, State)
    catch ?EXCEPTION(_ErrClass, _ErrReason, _Stacktrace) ->
        ?ERR("handle_call Request:~w, Error:~w", [Request, {_ErrClass, _ErrReason, ?GET_STACK(_Stacktrace)}]),
        {reply, error, State}
    end.

handle_cast(Msg, State) ->
    try
        do_handle_cast(Msg, State)
    catch ?EXCEPTION(_ErrClass, _ErrReason, _Stacktrace) ->
        ?ERR("handle_cast Msg:~w, Error:~w", [Msg, {_ErrClass, _ErrReason, ?GET_STACK(_Stacktrace)}]),
        {noreply, State}
    end.

handle_info(_Info, State) ->
    {noreply, State}.

terminate(_Reason, _State) ->
    ok.

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

do_handle_call(_Request, _From, State) ->
    {noreply, State}.

%% 添加注册服
do_handle_cast({add_svrs, CBMap}, {SrvZoneMap, ZoneInfo, SvrFactMap} = _State) ->
    #{
        add_servers := AddServers
    } = CBMap,
    F = fun({ServerId, ZoneId, FactId}, {Map1, Info, Map2}) ->
        NewSvrZoneMap1 = maps:put(ServerId, ZoneId, Map1),
        NewZoneInfo1 =
            case lists:keyfind(ZoneId, 1, Info) of
                {ZoneId, SrvList} ->
                    ?IF(lists:member(ServerId, SrvList), Info, lists:keystore(ZoneId, 1, Info, {ZoneId, [ServerId | SrvList]}));
                _ -> lists:keystore(ZoneId, 1, Info, {ZoneId, [ServerId]})
            end,
        NewSvrFMap1 = maps:put(ServerId, FactId, Map2),
        {NewSvrZoneMap1, NewZoneInfo1, NewSvrFMap1}
        end,
    {NewSvrZoneMap, NewZoneInfo, NewSvrFactMap} = lists:foldl(F, {SrvZoneMap, ZoneInfo, SvrFactMap}, AddServers),
    {noreply, {NewSvrZoneMap, NewZoneInfo, NewSvrFactMap}};

%% 重新分区更新数据
do_handle_cast({recalc_zone, CBMap}, _State) ->
    #{
        svr_zone_map := NewSvrZoneMap
    } = CBMap,
    ZoneIds = cross_zone:get_all_zone_ids(czone),
    NewZoneInfo = [begin
                       SrvList = cross_zone:get_zone_servers(czone, ZoneId),
                       {ZoneId, SrvList}
                   end || ZoneId <- ZoneIds],
    SvrFactMap = czone:get_faction_map(svr_faction_map),
    {noreply, {NewSvrZoneMap, NewZoneInfo, SvrFactMap}};

%% 跨服分区聊天
do_handle_cast({zone_chat, ServerId, BinData}, State) ->
    {SrvZoneMap, ZoneInfo, _} = State,
    ZoneId = maps:get(ServerId, SrvZoneMap, 0),
    case lists:keyfind(ZoneId, 1, ZoneInfo) of
        {_, SrvList} ->
            skip;
        _ ->
            SrvList = [ServerId]
    end,
    [clusters_center:apply_cast(SrvId, lib_server_send, send_to_all, [BinData]) || SrvId <- SrvList],
    {noreply, State};

%% 本国聊天
do_handle_cast({country_chat, ServerId, BinData}, State) ->
    {SrvZoneMap, _, SvrFactMap} = State,
    ZoneId = maps:get(ServerId, SrvZoneMap, 0),
    Faction = maps:get(ServerId, SvrFactMap, 0),
    czone:zone_faction_apply_cast(ZoneId, Faction, {lib_server_send, send_to_all, [BinData]}),
    {noreply, State}.