%% ---------------------------------------------------------------------------
%% @doc mod_team
%% @author ming_up@foxmail.com
%% @since  2016-11-01
%% @deprecated 组队进程模块
%% ---------------------------------------------------------------------------

-module(mod_team).
-behaviour(gen_server).

-export([start/1, cast_to_team/2, cast_to_team/3, cast_to_game/5, call_to_team/2, stop/1]).
-export([init/1, handle_call/3, handle_cast/2,
         handle_info/2, terminate/2, code_change/3]).
-include("common.hrl").
-include("server.hrl").
-include("scene.hrl").
-include("team.hrl").
-include("predefine.hrl").
-include("figure.hrl").

%% --------------------------------- 公共函数 ----------------------------------
start(Args) ->
    gen_server:start(?MODULE, Args, []).

cast_to_team(0, _Msg) ->
    ok;
cast_to_team(TeamId, Msg) when is_integer(TeamId)->
    % IsCenter = config:get_cls_type() == ?NODE_CENTER,
    % case TeamId rem 2 of 
    %     0 when not IsCenter -> %% 偶数为跨服队伍
    %         Node = clusters_node:get_node(),
    %         clusters_node:apply_cast(mod_team, cast_to_team, [Node, TeamId, Msg]);
    %     _ ->
            cast_to_team(undefined, TeamId, Msg);
    % end;

cast_to_team(TeamPid, Msg) when is_pid(TeamPid) ->
    gen_server:cast(TeamPid, {node(), Msg}).

cast_to_team(Node, TeamId, Msg) ->
    case ets:lookup(?ETS_TEAM, TeamId) of
        [#ets_team{pid=Pid}|_] -> gen_server:cast(Pid, {Node, Msg});
        _ ->
            case Msg of
                {quit_team, RoleId, _} ->
                    when_not_find_team(Node, RoleId, TeamId);
                {get_team_info, Id} ->
                    when_not_find_team(Node, Id, TeamId),
                    ok;
                _ ->
                    false
            end
    end.

%% 容错处理，没有找到队伍的时候，就退队吧
when_not_find_team(Node, RoleId, TeamId) ->
    {ok, Bin} = pt_240:write(24005, [1]),
    ClsType = config:get_cls_type(),
    case ClsType of
        ?NODE_CENTER -> lib_server_send:send_to_uid(Node, RoleId, Bin);
        _ -> lib_server_send:send_to_uid(RoleId, Bin)
    end,
    mod_team:cast_to_game(ClsType, Node, lib_player, update_player_info,
        [RoleId, [{team_flag, {TeamId, 0, 0, ""} }]]).

%% 同一节点请求队伍数据
call_to_team(TeamId, Msg) ->
    case ets:lookup(?ETS_TEAM, TeamId) of
        [#ets_team{pid=Pid}|_] -> gen_server:call(Pid, Msg);
        _ -> false
    end.

stop(TeamPid) ->
    gen_server:cast(TeamPid, stop).

cast_to_game(?NODE_CENTER, SerIdOrNode, M, F, A) -> clusters_center:apply_cast(SerIdOrNode, M, F, A);
cast_to_game(_, _, M, F, A) -> apply(M,F,A).

%% --------------------------------- 内部函数 ----------------------------------
%% 启动服务器.
init([TeamArgs]) ->
    process_flag(trap_exit, true),
    #team_args{
        id = TeamId, create_type = CreateType, act_id = ActivityId
        ,act_sub_id = SubTypeId, scene_id = _SceneId, join_type = JoinType
        ,password = Password, member = [LeaderInfo | _] = Mbs
        ,key_value_list = KeyValueList, lev_min = MinLev, lev_max = MaxLev
        ,is_allow_mem_invite = IsInvite, is_task = IsTask, power = Power
        ,is_matching = AutoMatch
    } = TeamArgs,
    NewKeyValueList = case MinLev > 0 andalso MaxLev > 0 of
        true -> [{lv, [MinLev, MaxLev]} | KeyValueList];
        _ -> KeyValueList
    end,
    {
        Module, SubModule, DunId, SceneId, LvMin, LvMax, TeamMemberMax
    } = case data_team_ui:get(ActivityId, SubTypeId) of
        [] ->
            {0, 0, 0, 0, 0, 0, ?TEAM_MEMBER_MAX};
        #team_enlist_cfg{
            module_id = Mod, sub_module = SubMod, dun_id = DunIdCfg, scene_id = SceneIdCfg,
            default_lv_min = LvMinCfg, default_lv_max = LvMaxCfg, num = TeamMemberMaxCfg
        } -> 
            {Mod, SubMod, DunIdCfg, SceneIdCfg, LvMinCfg, LvMaxCfg, TeamMemberMaxCfg}
    end,
    Enlist = #team_enlist{
        activity_id = ActivityId, subtype_id = SubTypeId, module_id = Module
        ,sub_module = SubModule, scene_id = SceneId, dun_id = DunId
    },
    #mb{id = LeaderId, pid = LPid, node = LNode, figure = LFigure} = LeaderInfo,
    #figure{name = LeaderName} = LFigure,
    ClsType = case TeamId rem 2 of 0 -> ?NODE_CENTER; _ -> ?NODE_GAME end,
    HisTeammate = [RoleId || #mb{id = RoleId} <- Mbs],
    Partners = [
        Figure || #mb{id = RoleId, figure = Figure} <- Mbs, RoleId =/= LeaderId
    ],
    {NewMemberList, FreeLocations} = lib_team:calc_location(Mbs, TeamMemberMax),
    DelayUpdateRef = case ClsType =:= ?NODE_GAME of
        true -> erlang:send_after(2000, self(), notify_teammates_update);
        _ -> undefined 
    end,
    State = #team{
        id = TeamId, pid = self(), cls_type = ClsType, leader_id = LeaderId
        ,leader_pid = LPid, leader_node = LNode, member = NewMemberList
        ,free_location = FreeLocations, enlist = Enlist, arbitrate = #team_arbitrate{}
        ,dungeon = #team_dungeon{}, his_teammate = HisTeammate, lv_limit_max = LvMax
        ,lv_limit_min = LvMin, max_num = TeamMemberMax, join_type = JoinType
        ,init_join_type = JoinType, delay_update_ref = DelayUpdateRef
        ,is_allow_mem_invite = IsInvite, is_task = IsTask, create_type = CreateType
        ,power_limit = Power, password = Password, leader_name = LeaderName
    },
    lib_team:update_ets_team(State),
    NewState = init_team_args(NewKeyValueList, State),
    lib_team:send_team_info(NewState),
    F1 = fun(EMb) ->
        #mb{id = EMbId, node = EMbNode, help_type = EMbHelpType} = EMb,
        TeamPosition = case EMb#mb.id =:= LeaderId of
            true -> ?TEAM_LEADER;
            _ -> ?TEAM_MEMBER
        end,
        UpdateArgs = [EMbId, [{team_flag, {TeamId, TeamPosition, TeamId, LeaderName}}]],
        cast_to_game(ClsType, EMbNode, lib_player, update_player_info, UpdateArgs),
        lib_player:apply_cast(
            EMbNode, EMbId, ?APPLY_CAST_STATUS, ?NOT_HAND_OFFLINE, lib_team
            ,update_help_type, [DunId, TeamId, EMbHelpType]
        )
    end,
    lists:map(F1, NewMemberList),
    #team{is_task = NewIsTask} = NewState,
    NewTeamArgs = TeamArgs#team_args{is_task = NewIsTask},
    InitArgs = get_init_args(NewTeamArgs, LeaderInfo),
    mod_team_enlist:add_team(
        ClsType, TeamId, ActivityId, SubTypeId, SceneId, 1, LFigure, Partners, JoinType, InitArgs
    ),
    NewState2 = if
        CreateType =:= ?CREATE_TYPE_TAKE_OVER ->
            {take_over, Info} = lists:keyfind(take_over, 1, NewKeyValueList),
            take_over_team(NewState, Info);
        true ->
            NewState
    end,
    AutoMatch =:= 1 andalso cast_to_team(TeamId, {set_matching_state, LeaderId, 1}),
    {ok, NewState2}.

%% 同步消息处理.
handle_call(Event, From, Status) ->
    mod_team_call:handle_call(Event, From, Status).

%% 异步消息处理.
handle_cast(Event, Status) ->
    #team{waiting_status = WaitingStatus} = Status,
    if
        is_record(WaitingStatus, waiting_status) ->
            MsgList = [{cast, Event}|WaitingStatus#waiting_status.msg_list],
            NowTime = utime:unixtime(),
            if
                NowTime - WaitingStatus#waiting_status.time < 5 ->
                    {noreply, Status#team{waiting_status = WaitingStatus#waiting_status{msg_list = MsgList}}};
                true ->
                    lib_team:handle_message(Status#team{waiting_status = []}, lists:reverse(MsgList))
            end;
        true ->
            mod_team_cast:handle_cast(Event, Status)
    end.

handle_info({ignore_waiting, Info}, Status) ->
    mod_team_info:handle_info(Info, Status);

%% handle_info信息处理
handle_info(Info, Status) ->
    #team{waiting_status = WaitingStatus} = Status,
    if
        is_record(WaitingStatus, waiting_status) ->
            MsgList = [{info, Info}|WaitingStatus#waiting_status.msg_list],
            NowTime = utime:unixtime(),
            if
                NowTime - WaitingStatus#waiting_status.time < 5 ->
                    {noreply, Status#team{waiting_status = WaitingStatus#waiting_status{msg_list = MsgList}}};
                true ->
                    lib_team:handle_message(Status#team{waiting_status = []}, lists:reverse(MsgList))
            end;
        true ->
            mod_team_info:handle_info(Info, Status)
    end.

%% 服务器停止.
terminate(_R, State) ->
    #team{id= TeamId, cls_type = ClsType, is_matching = MatchingState,
          enlist=#team_enlist{activity_id=ActivityId, subtype_id=SubTypeId, scene_id=SceneId}, member = MemberList} = State,
    lib_team:delete_ets_team(TeamId),
    [
        begin
            %%通知客户端
            {ok, BinData2} = pt_240:write(24005, [1]),
            lib_team:send_to_uid(Mb#mb.node, Mb#mb.id, BinData2),
            %%修改玩家数据
            cast_to_game(ClsType, Mb#mb.node, lib_player, update_player_info, [Mb#mb.id, [{team_flag, {TeamId, 0, 0, ""}}]])
        end
        ||Mb<-MemberList
    ],
    mod_team_enlist:delete_team(ClsType, TeamId, ActivityId, SubTypeId, SceneId),
    if
        MatchingState /= 0 ->
            case lib_team_match:get_match_mod(ActivityId, SubTypeId) of
                undefined ->
                    skip;
                Mod ->
                    Mod:team_set_match_state(State, 0)
            end;
        true ->
            skip
    end,
    % ?PRINT("team terminate ~p~n", [TeamId]),
    ok.

%% 热代码替换.
code_change(_OldVsn, State, _Extra)->
    {ok, State}.

get_init_args(TeamArgs, LeaderInfo) ->
    #team_args{
        lev_min = LvMin, lev_max = LvMax
        ,is_task = IsTask, leader_scene_id = Scene, leader_scene_pool_id = ScenePoolId
        ,leader_x = X, leader_y = Y, password = Password
    } = TeamArgs,
    [
        {lv, LvMin, LvMax}, {task,IsTask}, {online_flag, LeaderInfo#mb.online}
        ,{set_help_type, LeaderInfo#mb.help_type}
        ,{dungeon_count, LeaderInfo#mb.dungeon_count},
        {server_num, LeaderInfo#mb.server_num},
        {server_id, LeaderInfo#mb.server_id},
        {chat_zone, LeaderInfo#mb.chat_zone},
        {srv_open_time, LeaderInfo#mb.srv_open_time}
        ,{leader_scene_id, Scene}, {leader_scene_pool_id, ScenePoolId}
        ,{leader_x, X}, {leader_y, Y}, {password, Password}
    ].
init_team_args([{K, V}|T], State) ->
    NewState = case K of
        name -> State#team{name=V};
        join_type -> State#team{join_type=V};
        is_invite -> State#team{is_allow_mem_invite=V};
        create_type -> State#team{create_type=V};
        %% bonfire_ids -> State#team{bonfire_ids=V};
        lv ->
            [Min, Max] = V,
            State#team{lv_limit_min = Min, lv_limit_max = Max};
        task ->
            State#team{is_task=V};
        invite ->
           mod_team:cast_to_team(State#team.id, V),
           State;
        take_over ->
            State;
        _ ->
            State
    end,
    init_team_args(T, NewState);
init_team_args([], State) -> State.

take_over_team(State, Info) ->
    [OldTeamPid, ToArgs, BackArgs] = Info,
    NewTeamPid = self(),
    NewState = lib_team:take_over_team(State, ToArgs),
    OldTeamPid ! {ignore_waiting, {take_over_team_done, NewTeamPid, BackArgs}},
    NewState.
