%% ---------------------------------------------------------------------------
%% @doc mod_team_enlist
%% @author ming_up@foxmail.com
%% @since  2016-11-02
%% @deprecated  招募管理进程 %TODO
%% ---------------------------------------------------------------------------
-module(mod_team_enlist).
-behaviour(gen_server).

-export([
    start_link/0
    , cast_to_team_enlist/1
    , cast_to_team_enlist/2
    , add_team/10
    , delete_team/5
    , change_team/3
    , get_teams_num/2
    , clear_teams_reqlist_by_id/2
    , clear_role_match/1
    , change_role/2
    , match_teams/3
    , match_next/2
    , cast_to_team_enlist_by_team_id/2

    , set_up_password/7
    , gm_clear_team_state/0
    ]).
-export([init/1, handle_call/3, handle_cast/2,
         handle_info/2, terminate/2, code_change/3]).

-include("common.hrl").
-include("server.hrl").
-include("team.hrl").
-include("errcode.hrl").
-include("predefine.hrl").
-include("figure.hrl").
-include("role.hrl").
-include("dungeon.hrl").
-include("unite.hrl").

-record(state, {team_maps=#{}, activity_maps=#{}, num_maps=#{}, match_roles_map = #{}, zone_maps = #{}}).
-record(team_enlist_info, {
        team_id,
        num,
        max_num = ?TEAM_MEMBER_MAX,
        join_type = 1,                  %% 1:不自动，2:自动
        leader_figure,
        leader_online = ?ONLINE_ON,
        dungeon_count = [],             %% 副本次数
        leader_help_type = 0,
        leader_help_counts = 0,
        leader_server = 0,              %% server_num
        leader_server_id = 0,           %% server_id
        leader_chat_zone = 0,           %% 跨服聊天分区号
        leader_srv_open_time = 0,       %% 游戏服开服时间
        leader_scene_id = 0,            %% 队长所在场景id
        leader_x = 0,                   %% 队长x坐标
        leader_y = 0,                   %% 队长y坐标
        activity_id,
        scene_id,
        dungeon_type = 0 ,
        matching = 0 ,                  %% 是否为自动匹配状态
        lv_limit_min = 0,               %% 等级下限
        lv_limit_max = 0,               %% 等级上限
        subtype_id = 0,
        partner = [],                   %% 队伍伙伴[RoleId,...]
        is_task = false,                %% 任务队伍不参与真实玩家匹配
        password = <<>>,                %% 只有队长可设置 "10000"默认不限制
        power_limit = 0                 %% 战力限制
    }).
-record(matching_role, {
        node = undefined,
        role_id,                        %% 玩家id
        activity_list,                  %% 想匹配的活动
        waiting_team_ids,               %% 可以匹配的队伍id列表
        match_time = 0,                 %% 执行匹配的时间
        lv = 0,                         %% 玩家等级
        power = 0,                      %% 玩家战力
        ref = 0                         %% 本次匹配的标识
    }).

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

%% 添加组队平台信息
add_team(ClsType, TeamId, ActivityId, SubTypeId, SceneId, Num, LeaderFigure, Partner, JoinType, Args) ->
    cast_to_team_enlist(ClsType, {'add_team', TeamId, ActivityId, SubTypeId, SceneId, Num, LeaderFigure, Partner, JoinType, Args}).

%% 移除组队平台信息
delete_team(ClsType, TeamId, ActivityId, SubTypeId, SceneId) ->
    cast_to_team_enlist(ClsType, {'delete_team', TeamId, ActivityId, SubTypeId, SceneId}).

%% 更改队伍信息
change_team(ClsType, TeamId, KeyValues) ->
    cast_to_team_enlist(ClsType, {'change_team', TeamId, KeyValues}).

%% 批量查看队伍人数
get_teams_num(Sid, TeamIds) ->
    cast_to_team_enlist({'get_teams_num', Sid, TeamIds}).

%% 设置队伍密码和战力限制
set_up_password(ClsType, Node, Sid, RoleId, TeamId, Password, Power) ->
    cast_to_team_enlist(ClsType, {'set_up_password', Node, Sid, RoleId, TeamId, Password, Power}).

%% 清理所有队伍申请列表里某个玩家
clear_teams_reqlist_by_id(RoleId, TeamIds) ->
    F = fun(Id) -> lib_team:get_team_cls_type(Id) =:= ?NODE_GAME end,
    {NodeTeams, CenterTeams} = lists:partition(F, TeamIds),
    NodeTeams =/= [] andalso
        cast_to_team_enlist({'clear_teams_reqlist_by_id', RoleId, TeamIds}),
    CenterTeams =/= [] andalso
        cast_to_team_enlist(?NODE_CENTER, {'clear_teams_reqlist_by_id', RoleId, TeamIds}).

%% 清理玩家匹配状态
clear_role_match(RoleId) ->
    cast_to_team_enlist(?NODE_CENTER, {'clear_role_match', RoleId}),
    cast_to_team_enlist({'clear_role_match', RoleId}).

%% 修改匹配玩家信息
change_role(RoleId, KeyValues) ->
    cast_to_team_enlist({'change_role', RoleId, KeyValues}).

%% 匹配队伍
match_teams(Mb, Sid, ActivityList)->
    cast_to_team_enlist({'match_teams', Mb, Sid, ActivityList}).
    


%% 匹配下一个队伍
match_next(Mb, [Node, Ref]) ->
    unode:apply(Node, mod_team_enlist, cast_to_team_enlist, [{'match_next', Mb, Ref}]).

%% gm操作
gm_clear_team_state() ->
    ClsType = config:get_cls_type(),
    cast_to_team_enlist(ClsType, {'gm_clear_team_state'}).

cast_to_team_enlist_by_team_id(TeamId, Msg) ->
    ClsType = lib_team:get_team_cls_type(TeamId),
    cast_to_team_enlist(ClsType, Msg).

cast_to_team_enlist(Msg) ->
    gen_server:cast(?MODULE, Msg).

cast_to_team_enlist(ClsType, Msg) ->
    case config:get_cls_type() of
        ClsType ->
            cast_to_team_enlist(Msg);
        ?NODE_GAME ->
            clusters_node:apply_cast(mod_team_enlist, cast_to_team_enlist, [Msg]);
        _ -> %% 跨服节点不能去调用未知的游戏节点
            ok
    end.

init([]) ->
    F = fun(E, Maps) ->
            Maps#{E => []}
    end,
    {ok, #state{num_maps=lists:foldl(F, #{}, lists:seq(1, ?TEAM_MEMBER_MAX))}}.

handle_call(_Event, _From, Status) ->
    {noreply, Status, Status}.

handle_cast({'get_all_team', Sid, ActivityId, SubTypeId, SceneId, _ServerNum, RoleServerId, _ChatZone, _OpenDay}, State) ->
    #state{team_maps=TeamMaps, activity_maps=ActivityMaps} = State,
    %% IsZoneTeam是跨服组队分区功能的分区划分
    IsZoneTeam  = lists:member(SceneId, ?ZONE_PARTITION),
    ZoneId      = get_team_zone_id(RoleServerId),
    TeamIds     = get_teams(IsZoneTeam, ActivityId, SubTypeId, ZoneId, ActivityMaps),
    Max = 100,
    F = fun
        (_, {Result, Counts}) when Counts >= Max ->
            {Result, Counts};
        (TeamId, {Result, Counts}) ->
            TeamEnlistInfo = maps:get(TeamId, TeamMaps, false),
            case TeamEnlistInfo of
                #team_enlist_info{num=Num, max_num = NumMax} when Num >= NumMax ->
                    {Result, Counts};

                #team_enlist_info{
                    leader_figure=LF, leader_server = Server,num=Num, lv_limit_min = LvMin,
                    lv_limit_max = LvMax, leader_online = LeaderOnline, dungeon_count = _DungeonCount,
                    dungeon_type = DungeonType, join_type = JoinType, partner = Partner, password = Password,
                    leader_help_type = HelpType, leader_help_counts = HelpCounts, power_limit = PowerLimit, 
                    leader_scene_id = LeaderScene,leader_x = LeaderX, leader_y = LeaderY
                } ->
                    %% 还没进入副本的队伍才显示
                    case DungeonType == 0 of
                        true->
                            case lists:keyfind(TeamId, 1, Result) of
                                {TeamId, _, _}->
                                    {Result, Counts};
                                false ->
                                    DunCounts = 1,
                                    SSS = [{RoleId, Sex, Career, Picture, Ver, Turn} ||
                                        #figure{id = RoleId, sex = Sex, career = Career, picture = Picture, picture_ver = Ver, turn = Turn} <- Partner
                                    ],
                                    TeamShowInfo = {
                                        TeamId, LF, Num, JoinType, LvMin, LvMax, SSS,
                                        LeaderOnline, DunCounts, HelpType, HelpCounts 
                                        ,Server, Password, PowerLimit, ActivityId, SubTypeId, SceneId
                                        ,LeaderScene, LeaderX, LeaderY
                                    },
                                    {[TeamShowInfo | Result], Counts+1}
                            end;
                        false->
                            {Result, Counts}
                    end;
                _ ->
                    {Result, Counts}
            end
    end,
    {List, _} = lists:foldl(F, {[], 0}, TeamIds),
    {ok, BinData} = pt_240:write(24012, [List]),
    ClsType = config:get_cls_type(),
    if ClsType =:= ?NODE_CENTER ->
            RoleNode = clusters_center:find_node(RoleServerId),
            lib_server_send:send_to_sid(RoleNode, Sid, BinData);
        true ->
            lib_server_send:send_to_sid(Sid, BinData)
    end,
    {noreply, State};

%%进出副本切换状态--zzy
handle_cast({'change_dungeon_type', TeamId, Type }, State) ->
    #state{team_maps=TeamMaps} = State,
    NewState = case maps:get(TeamId, TeamMaps, false) of
        false ->
            State;
        #team_enlist_info{} = TeamInfo ->
            NewTeamInfo = case Type =:= into of
                true->
                    TeamInfo#team_enlist_info{ dungeon_type = 1 };
                false->
                    TeamInfo#team_enlist_info{ dungeon_type = 0 }
            end,
            NewTeamMaps = maps:put(TeamId,NewTeamInfo, TeamMaps),
            State#state{team_maps = NewTeamMaps}
    end,
    {noreply, NewState};

handle_cast({'add_team', TeamId, ActivityId, SubTypeId, SceneId, Num, LeaderFigure, Partner, JoinType, Args}, State) ->
    #state{team_maps=TeamMaps, activity_maps=ActivityMaps, match_roles_map = MatchRolesMap, zone_maps = ZoneMaps} = State,
    MaxNum = lib_team:get_max_team_member_num(ActivityId, SubTypeId),
    Info0  = #team_enlist_info{team_id=TeamId, num=Num, leader_figure=LeaderFigure, join_type = JoinType,
        activity_id = ActivityId, scene_id = SceneId, subtype_id = SubTypeId, max_num = MaxNum, partner = Partner},
    Info = fill_team_info_args(Info0, Args),
    NewTeamMaps = TeamMaps#{TeamId => Info},
    IsZoneTeam = lists:member(SceneId, ?ZONE_PARTITION),
    ZoneId = if IsZoneTeam ->
            get_team_zone_id(Info#team_enlist_info.leader_server_id);
        true ->
            0
    end,
    TeamIds = get_teams(IsZoneTeam, ActivityId, SubTypeId, ZoneId, ActivityMaps),
    NewTeamIds = case lists:member(TeamId, TeamIds) of
        true ->
            TeamIds;
        _ ->
            [TeamId|TeamIds]
    end,
    NewActivityMaps   = put_teams(IsZoneTeam, ActivityId, SubTypeId, ZoneId, NewTeamIds, ActivityMaps),
    NewMatchRolesMap  = update_match_roles(Args, TeamId, NewTeamMaps, MatchRolesMap),

    NewZoneMaps = update_zone_team(IsZoneTeam, add, ZoneId, TeamId, ZoneMaps),

    {noreply, State#state{team_maps = NewTeamMaps, activity_maps = NewActivityMaps, match_roles_map = NewMatchRolesMap, zone_maps = NewZoneMaps}};

handle_cast({'delete_team', TeamId, ActivityId, SubTypeId, SceneId}, State) ->
    #state{team_maps = TeamMaps, activity_maps = ActivityMaps, zone_maps = ZoneMaps} = State,
    ZoneId = maps:get(TeamId, ZoneMaps, 0),

    NewTeamMaps = maps:remove(TeamId, TeamMaps),

    IsZoneTeam  = lists:member(SceneId, ?ZONE_PARTITION),
    TeamIds = get_teams(IsZoneTeam, ActivityId, SubTypeId, ZoneId, ActivityMaps),
    NewTeamIds = lists:delete(TeamId, TeamIds),
    NewActivityMaps = put_teams(IsZoneTeam, ActivityId, SubTypeId, ZoneId, NewTeamIds, ActivityMaps),
    % NewActivityMaps = ActivityMaps#{{ActivityId, SubTypeId} => lists:delete(TeamId, maps:get({ActivityId, SubTypeId}, ActivityMaps, []))},

    NewZoneMaps = update_zone_team(IsZoneTeam, delete, ZoneId, TeamId, ZoneMaps),

    {noreply, State#state{team_maps = NewTeamMaps, activity_maps = NewActivityMaps, zone_maps = NewZoneMaps}};

handle_cast({'change_team', TeamId, KeyValues}, State) ->
    #state{team_maps=TeamMaps, activity_maps=ActivityMaps, num_maps=NumMaps, match_roles_map = MatchRolesMap} = State,
    {NewTeamMaps, NewActivityMaps, NewNumMaps} = change_team(KeyValues, TeamId, TeamMaps, ActivityMaps, NumMaps),
    NewMatchRolesMap = update_match_roles(KeyValues, TeamId, NewTeamMaps, MatchRolesMap),
    {noreply, State#state{team_maps=NewTeamMaps, activity_maps=NewActivityMaps, num_maps=NewNumMaps, match_roles_map = NewMatchRolesMap}};

handle_cast({'get_teams_num', Sid, TeamIds}, State) ->
    #state{team_maps=TeamMaps} = State,
    F = fun(TeamId, Result) ->
            case maps:get(TeamId, TeamMaps, false) of
                false -> Result;
                TeamInfo -> [{TeamInfo#team_enlist_info.leader_figure ,TeamId, TeamInfo#team_enlist_info.num, TeamInfo#team_enlist_info.activity_id, TeamInfo#team_enlist_info.subtype_id} | Result]
            end
    end,
    % ?INFO("~p~n",[lists:foldl(F, [], TeamIds)]),
    {ok, BinData} = pt_240:write(24032, [ lists:foldl(F, [], TeamIds) ]),
    lib_server_send:send_to_sid(Sid, BinData),
    {noreply, State};


%%任务玩家不参与匹配和进入他人队伍  自己组队招机器人
handle_cast({'match_teams', Mb, Sid, ActivityList}, State) ->
    [{ActId, SubId}|_] = ActivityList,
    {ok, BinData} = pt_240:write(24023, [?SUCCESS, ActId, SubId]),
    lib_server_send:send_to_sid(Sid, BinData),
    #state{team_maps = TeamMaps, activity_maps = ActivityMaps, match_roles_map = MatchRolesMap} = State,
    #mb{id = RoleId, server_id = ServerId, figure = #figure{lv = Lv, power = Power}, node = Node} = Mb,
    MatchRole0 = maps:get(RoleId, MatchRolesMap, #matching_role{role_id = RoleId, node = Node}),
    %% 检查满员情况
    F1 = fun(TeamId)->
        case maps:get(TeamId, TeamMaps, false) of
            #team_enlist_info{num=Num, matching = 1, max_num = NumMax,is_task=false} when Num < NumMax ->
                true;
            _ ->
                % mod_team:cast_to_team(TeamId,  {'join_team_request', Mb})
                false
        end
    end,
     % ?ERR("~p ~p", [ZoneId, ActivityMaps]),


    F = fun({ActivityId, SubTypeId}, Acc)->
        case data_team_ui:get(ActivityId, SubTypeId) of
            #team_enlist_cfg{scene_id = SceneId} ->
                case lists:member(SceneId, ?ZONE_PARTITION) of
                    IsZoneTeam = true ->
                        ZoneId = get_team_zone_id(ServerId),
                        TeamIds = get_teams(IsZoneTeam, ActivityId, SubTypeId, ZoneId, ActivityMaps),
                        [Id || Id <- TeamIds, F1(Id)] ++ Acc;
                    _ ->
                        TeamIds = maps:get({ActivityId,SubTypeId},ActivityMaps,[]),
                        [Id || Id <- TeamIds, F1(Id)] ++ Acc
                end;
            _ ->
                TeamIds = maps:get({ActivityId,SubTypeId},ActivityMaps,[]),
                [Id || Id <- TeamIds, F1(Id)] ++ Acc
        end
    end,
    AvailableList0 = lists:foldl(F, [], ActivityList),
    AvailableList  = case Mb#mb.is_task == true of
        true->
            [];
        _->
            AvailableList0
    end,
    MatchRole1 = MatchRole0#matching_role{
        ref = MatchRole0#matching_role.ref + 1,
        activity_list = ActivityList,
        waiting_team_ids = AvailableList,
        match_time = utime:unixtime(),
        lv = Lv, power = Power
        },
    NewMatchRolesMap = match_team_request(MatchRolesMap, MatchRole1, Mb, TeamMaps),
    {noreply, State#state{match_roles_map = NewMatchRolesMap}};

handle_cast({'near_teams_match', Sid, Mb, TeamList}, State) ->
    {ok, BinData} = pt_240:write(24044, [?SUCCESS]),
    lib_server_send:send_to_sid(Sid, BinData),
    #state{team_maps = TeamMaps, match_roles_map = MatchRolesMap} = State,
    #mb{id = RoleId, figure = #figure{lv = Lv}} = Mb,
    MatchRole0 = maps:get(RoleId, MatchRolesMap, #matching_role{role_id = RoleId}),
    F = fun(TeamId)->
        case maps:get(TeamId, TeamMaps, false) of
            #team_enlist_info{num=Num, matching = 1, max_num = NumMax} when Num < NumMax ->
                true;
            _ ->
                % mod_team:cast_to_team(TeamId,  {'join_team_request', Mb})
                false
        end
    end,
    AvailableList = [TeamId || TeamId <- TeamList, F(TeamId)],
    MatchRole1 = MatchRole0#matching_role{
        ref = MatchRole0#matching_role.ref + 1,
        activity_list = [],
        waiting_team_ids = AvailableList,
        match_time = utime:unixtime(),
        lv = Lv
        },
    NewMatchRolesMap = match_team_request(MatchRolesMap, MatchRole1, Mb, TeamMaps),
    {noreply, State#state{match_roles_map = NewMatchRolesMap}};

handle_cast({'personal_find_team', ActivityId, SubTypeId, _SceneId, Mb}, #state{num_maps=NumMaps} = State) ->
    %% todo 取消匹配状态
    MaxNum = lib_team:get_max_team_member_num(ActivityId, SubTypeId),
    case MaxNum - 1 of
        NeedNum when NeedNum>0 andalso NeedNum<MaxNum ->
            case find_a_team(NeedNum, NumMaps) of
                false  -> {noreply, State};
                TeamId ->
                    mod_team:cast_to_team(TeamId, {'join_team_request', Mb})
            end;
        _ ->
            {noreply, State}
    end;

handle_cast({'clear_teams_reqlist_by_id', RoleId, TeamIds}, State) ->
    #state{team_maps = TeamMaps} = State,
    F = fun(TeamId)->
        case maps:get(TeamId, TeamMaps, false) of
            false ->  skip;
            _ ->
                mod_team:cast_to_team(TeamId,  {'clear_teams_reqlist_by_id', RoleId})
        end
    end,
    lists:map(F,TeamIds),
    {noreply, State};

handle_cast({'clear_role_match', RoleId}, State) ->
    #state{match_roles_map = Map} = State,
    case maps:is_key(RoleId, Map) of
        true ->
            NewMap = maps:remove(RoleId, Map),
            {noreply, State#state{match_roles_map = NewMap}};
        _ ->
            {noreply, State}
    end;

handle_cast({'match_next', Mb, Ref}, State) ->
    #state{match_roles_map = Map, team_maps = TeamMaps} = State,
    case maps:find(Mb#mb.id, Map) of
        {ok, #matching_role{ref = Ref} = R} ->
            #mb{figure = #figure{lv = Lv}} = Mb,
            NewMap = match_team_request(Map, R#matching_role{match_time = utime:unixtime(), lv = Lv}, Mb, TeamMaps),
            {noreply, State#state{match_roles_map = NewMap}};
        _ ->
            {noreply, State}
    end;

handle_cast({'change_role', RoleId, KeyValues}, State) ->
    #state{match_roles_map = MatchRolesMap} = State,
    case maps:get(RoleId, MatchRolesMap, false) of
        #matching_role{} = MatchRole ->
            NewMatchRole = change_role_helper(MatchRole, KeyValues),
            NewMatchRolesMap = MatchRolesMap#{RoleId => NewMatchRole},
            {noreply, State#state{match_roles_map = NewMatchRolesMap}};
        _ ->
            {noreply, State}
    end;






handle_cast({'set_up_password', Node, Sid, RoleId, TeamId, Password, Power}, State) ->
    #state{team_maps = TeamMaps} = State,
    case maps:get(TeamId, TeamMaps, false) of
        TeamInfo = #team_enlist_info{} ->
            #team_enlist_info{
                leader_figure = LeaderFigure,
                activity_id = ActId, subtype_id = SubTypeId
            } = TeamInfo,
            if LeaderFigure#figure.id =/= RoleId ->
                    {ok, BinData} = pt_240:write(24058, [?ERRCODE(err240_not_leader)]),
                    unode:apply(Node, lib_server_send, send_to_sid, [Sid, BinData]),
                    NewState = State;
                true ->
                    case data_team_ui:get(ActId, SubTypeId) of
                        #team_enlist_cfg{dun_id = DunId} ->
                            case data_dungeon:get_dun(DunId) of
                                #dun_cfg{type = ?DUNGEON_TYPE_TOWER} ->
                                    NewTeamMaps = maps:put(TeamId, TeamInfo#team_enlist_info{password = Password, power_limit = Power}, TeamMaps),
                                    %% 同步数据
                                    mod_team:cast_to_team(TeamId, {'set_up_password', Node, RoleId, Password, Power}),
                                    {ok, BinData} = pt_240:write(24058, [?SUCCESS]),
                                    unode:apply(Node, lib_server_send, send_to_sid, [Sid, BinData]),
                                    NewState = State#state{team_maps = NewTeamMaps};
                                _ ->
                                    {ok, BinData} = pt_240:write(24058, [?ERRCODE(err240_cannot_set_password)]),
                                    unode:apply(Node, lib_server_send, send_to_sid, [Sid, BinData]),
                                    NewState = State
                            end;
                        _ ->
                            {ok, BinData} = pt_240:write(24058, [?ERRCODE(err240_act_not_exist)]),
                            unode:apply(Node, lib_server_send, send_to_sid, [Sid, BinData]),
                            NewState = State
                    end
            end;
        _ ->
            {ok, BinData} = pt_240:write(24058, [?ERRCODE(err240_team_not_exist)]),
            unode:apply(Node, lib_server_send, send_to_sid, [Sid, BinData]),
            NewState = State
    end,
    {noreply, NewState};

handle_cast({'gm_clear_team_state'}, State) ->
    #state{activity_maps = ActivityMaps} = State,
    KeyList = [],
    NewActivityMaps = lists:foldl(fun({TypeId, SubTypeId}, TmpActivityMaps) ->
       #team_enlist_cfg{scene_id = SceneId} = data_team_ui:get(TypeId, SubTypeId),
       case lists:member(SceneId, ?ZONE_PARTITION) of
            true ->
                maps:remove({TypeId, SubTypeId}, TmpActivityMaps);
            _ ->
                TmpActivityMaps
        end
     end, ActivityMaps, KeyList),
    {noreply, State#state{activity_maps = NewActivityMaps}};

handle_cast(_Event, Status) ->
    {noreply, Status}.

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

terminate(_R, _State) ->
    ok.

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


get_teams(true, ActivityId, SubTypeId, ZoneId, ActivityMaps) ->
    % ZoneId = get_team_zone_id(ServId),
    TeamIds = maps:get({ActivityId, SubTypeId}, ActivityMaps, []),
    if ZoneId == 0 -> [];
        true ->
            case lists:keyfind(ZoneId, 1, TeamIds) of
                {ZoneId, ZoneTeamIds} ->
                    ZoneTeamIds;
                _ ->
                    []
            end
    end;
get_teams(false, ActivityId, SubTypeId, _, ActivityMaps) ->
    maps:get({ActivityId, SubTypeId}, ActivityMaps, []).


put_teams(true, ActivityId, SubTypeId, ZoneId, TeamIds, ActivityMaps) ->
    AllTeamIds = maps:get({ActivityId, SubTypeId}, ActivityMaps, []),
    NewTeamIds = lists:keystore(ZoneId, 1, AllTeamIds, {ZoneId, TeamIds}),
    ActivityMaps#{{ActivityId, SubTypeId} => NewTeamIds};
put_teams(false, ActivityId, SubTypeId, _ZoneId, TeamIds, ActivityMaps) ->
    ActivityMaps#{{ActivityId, SubTypeId} => TeamIds}.

update_zone_team(true, add, ZoneId, TeamId, ZoneMaps) ->
    case maps:get(TeamId, ZoneMaps, false) of
        ZoneId ->
            ZoneMaps;
        _ ->
            maps:put(TeamId, ZoneId, ZoneMaps)
    end;
update_zone_team(true, delete, _ZoneId, TeamId, ZoneMaps) ->
    maps:remove(TeamId, ZoneMaps);
update_zone_team(false, _, _ZoneId, _TeamId, ZoneMaps) ->
    ZoneMaps.


%% 默认1
get_team_zone_id(_ServId) -> 1.

%% 根据已有人数找寻一个适合人数的队伍
find_a_team(MbsLen, _) when MbsLen < 1 -> false;
find_a_team(MbsLen, NumMaps) ->
    case maps:get(MbsLen, NumMaps, false) of
        []    -> find_a_team(MbsLen-1, NumMaps);
        false -> find_a_team(MbsLen-1, NumMaps);
        [H|_] -> H
    end.

change_team([{num, AddNum}|T], TeamId, TeamMaps, ActivityMaps, NumMaps) ->
    case maps:get(TeamId, TeamMaps, 0) of
        0 -> change_team(T, TeamId, TeamMaps, ActivityMaps, NumMaps);
        #team_enlist_info{num=OldNum} = TeamEnlistInfo ->
            NewTeamMaps = TeamMaps#{TeamId := TeamEnlistInfo#team_enlist_info{num=max(0, OldNum+AddNum)}},
            change_team(T, TeamId, NewTeamMaps, ActivityMaps, NumMaps)
    end;
change_team([{leader, {Leaderfigure, Server}}|T], TeamId, TeamMaps, ActivityMaps, NumMaps) ->
    case maps:get(TeamId, TeamMaps, 0) of
        0 -> change_team(T, TeamId, TeamMaps, ActivityMaps, NumMaps);
        TeamEnlistInfo ->
            NewTeamMaps = TeamMaps#{TeamId := TeamEnlistInfo#team_enlist_info{leader_figure=Leaderfigure, leader_server = Server} },
            change_team(T, TeamId, NewTeamMaps, ActivityMaps, NumMaps)
    end;
change_team([{matching, V}|T], TeamId, TeamMaps, ActivityMaps, NumMaps) ->
    case maps:get(TeamId, TeamMaps, 0) of
        0 -> change_team(T, TeamId, TeamMaps, ActivityMaps, NumMaps);
        TeamEnlistInfo ->
            NewTeamMaps = TeamMaps#{TeamId := TeamEnlistInfo#team_enlist_info{matching = V} },
            change_team(T, TeamId, NewTeamMaps, ActivityMaps, NumMaps)
    end;
change_team([{join_type, V}|T], TeamId, TeamMaps, ActivityMaps, NumMaps) ->
    case maps:get(TeamId, TeamMaps, 0) of
        0 -> change_team(T, TeamId, TeamMaps, ActivityMaps, NumMaps);
        TeamEnlistInfo ->
            NewTeamMaps = TeamMaps#{TeamId := TeamEnlistInfo#team_enlist_info{join_type = V} },
            change_team(T, TeamId, NewTeamMaps, ActivityMaps, NumMaps)
    end;
change_team([{enlist, #team_enlist{activity_id=OldAcId, subtype_id=OldSubId}, #team_enlist{activity_id=AcId, subtype_id=SubId}}|T], TeamId, TeamMaps, ActivityMaps, NumMaps) ->
    OldActivityMaps = case maps:get({OldAcId, OldSubId}, ActivityMaps, []) of
        []   -> ActivityMaps;
        List -> ActivityMaps#{ {OldAcId, OldSubId} := lists:delete(TeamId, List) }
    end,
    NewActivityMaps = OldActivityMaps#{ {AcId, SubId} => [TeamId|lists:delete(TeamId, maps:get({AcId, SubId}, OldActivityMaps, []))] },
    case maps:get(TeamId, TeamMaps, 0) of
        0 -> change_team(T, TeamId, TeamMaps, NewActivityMaps, NumMaps);
        TeamEnlistInfo ->
            MaxNum = lib_team:get_max_team_member_num(AcId, SubId),
            NewTeamMaps = TeamMaps#{TeamId := TeamEnlistInfo#team_enlist_info{activity_id=AcId, subtype_id = SubId, max_num = MaxNum} },
            change_team(T, TeamId, NewTeamMaps, NewActivityMaps, NumMaps)
    end;
change_team([{lv, Min, Max}|T], TeamId, TeamMaps, ActivityMaps, NumMaps) ->
    case maps:get(TeamId, TeamMaps, 0) of
        0 -> change_team(T, TeamId, TeamMaps, ActivityMaps, NumMaps);
        TeamEnlistInfo ->
            NewTeamMaps = TeamMaps#{TeamId := TeamEnlistInfo#team_enlist_info{lv_limit_min = Min, lv_limit_max = Max} },
            change_team(T, TeamId, NewTeamMaps, ActivityMaps, NumMaps)
    end;
change_team([{add_partner, AddRole}|T], TeamId, TeamMaps, ActivityMaps, NumMaps) ->
    case maps:get(TeamId, TeamMaps, 0) of
        0 -> change_team(T, TeamId, TeamMaps, ActivityMaps, NumMaps);
        TeamEnlistInfo = #team_enlist_info{partner = Partner} ->
            NewTeamMaps = TeamMaps#{TeamId := TeamEnlistInfo#team_enlist_info{partner = [AddRole|Partner]}},
            change_team(T, TeamId, NewTeamMaps, ActivityMaps, NumMaps)
    end;
change_team([{name, Name}|T], TeamId, TeamMaps, ActivityMaps, NumMaps) ->
    case maps:get(TeamId, TeamMaps, 0) of
        0 -> change_team(T, TeamId, TeamMaps, ActivityMaps, NumMaps);
        TeamEnlistInfo = #team_enlist_info{leader_figure = Figure} ->
            NewTeamMaps = TeamMaps#{TeamId := TeamEnlistInfo#team_enlist_info{leader_figure = Figure#figure{name = Name}}},
            change_team(T, TeamId, NewTeamMaps, ActivityMaps, NumMaps)
    end;
change_team([{lv, Lv}|T], TeamId, TeamMaps, ActivityMaps, NumMaps) ->
    case maps:get(TeamId, TeamMaps, 0) of
        0 -> change_team(T, TeamId, TeamMaps, ActivityMaps, NumMaps);
        TeamEnlistInfo = #team_enlist_info{leader_figure = Figure} ->
            NewTeamMaps = TeamMaps#{TeamId := TeamEnlistInfo#team_enlist_info{leader_figure = Figure#figure{lv = Lv}}},
            change_team(T, TeamId, NewTeamMaps, ActivityMaps, NumMaps)
    end;
change_team([{power, Power}|T], TeamId, TeamMaps, ActivityMaps, NumMaps) ->
    case maps:get(TeamId, TeamMaps, 0) of
        0 -> change_team(T, TeamId, TeamMaps, ActivityMaps, NumMaps);
        TeamEnlistInfo = #team_enlist_info{leader_figure = Figure} ->
            NewTeamMaps = TeamMaps#{TeamId := TeamEnlistInfo#team_enlist_info{leader_figure = Figure#figure{power = Power}}},
            change_team(T, TeamId, NewTeamMaps, ActivityMaps, NumMaps)
    end;
change_team([{quit_partner, DeleteRoleId}|T], TeamId, TeamMaps, ActivityMaps, NumMaps) ->
    case maps:get(TeamId, TeamMaps, 0) of
        0 -> change_team(T, TeamId, TeamMaps, ActivityMaps, NumMaps);
        TeamEnlistInfo = #team_enlist_info{partner = Partner} ->
            NewTeamMaps = TeamMaps#{TeamId := TeamEnlistInfo#team_enlist_info{partner = lists:keydelete(DeleteRoleId, #figure.id, Partner)}},
            change_team(T, TeamId, NewTeamMaps, ActivityMaps, NumMaps)
    end;
change_team([{leader_online, {Leader, OnlineFlag}}|T], TeamId, TeamMaps, ActivityMaps, NumMaps) ->
    case maps:get(TeamId, TeamMaps, 0) of
        TeamEnlistInfo = #team_enlist_info{leader_figure = #figure{id = Leader}} ->
            NewTeamMaps = TeamMaps#{TeamId := TeamEnlistInfo#team_enlist_info{leader_online = OnlineFlag}},
            change_team(T, TeamId, NewTeamMaps, ActivityMaps, NumMaps);
        _ -> change_team(T, TeamId, TeamMaps, ActivityMaps, NumMaps)
    end;
% set_help_type
change_team([{set_help_type, {Leader, HelpType}}|T], TeamId, TeamMaps, ActivityMaps, NumMaps) ->
    case maps:get(TeamId, TeamMaps, 0) of
        TeamEnlistInfo = #team_enlist_info{leader_figure = #figure{id = Leader}, activity_id = ActId, subtype_id = SubId} ->
            NewTeamMaps = TeamMaps#{TeamId := TeamEnlistInfo#team_enlist_info{leader_help_type = HelpType}},
            %% 更新助战类型的时候刷新助战次数
            lib_team:update_help_counts(Leader, TeamId, ActId, SubId),
            change_team(T, TeamId, NewTeamMaps, ActivityMaps, NumMaps);
        _ -> change_team(T, TeamId, TeamMaps, ActivityMaps, NumMaps)
    end;
change_team([{help_counts, {Leader, Counts}}|T], TeamId, TeamMaps, ActivityMaps, NumMaps) ->
    case maps:get(TeamId, TeamMaps, 0) of
        TeamEnlistInfo = #team_enlist_info{leader_figure = #figure{id = Leader}} ->
            NewTeamMaps = TeamMaps#{TeamId := TeamEnlistInfo#team_enlist_info{leader_help_counts = Counts}},
            change_team(T, TeamId, NewTeamMaps, ActivityMaps, NumMaps);
        _ -> change_team(T, TeamId, TeamMaps, ActivityMaps, NumMaps)
    end;
change_team([{dungeon_count, {Leader, DungeonCount}}|T], TeamId, TeamMaps, ActivityMaps, NumMaps) ->
    case maps:get(TeamId, TeamMaps, 0) of
        TeamEnlistInfo = #team_enlist_info{leader_figure = #figure{id = Leader}} ->
            NewTeamMaps = TeamMaps#{TeamId := TeamEnlistInfo#team_enlist_info{dungeon_count = DungeonCount}},
            change_team(T, TeamId, NewTeamMaps, ActivityMaps, NumMaps);
        _ -> change_team(T, TeamId, TeamMaps, ActivityMaps, NumMaps)
    end;
change_team([{leader_position_xy, {LeaderId, Scene, X, Y}}|T], TeamId, TeamMaps, ActivityMaps, NumMaps) ->
    case maps:get(TeamId, TeamMaps, 0) of
        TeamEnlistInfo = #team_enlist_info{leader_figure = #figure{id = LeaderId}} ->
            TeamEnlistInfo2 = TeamEnlistInfo#team_enlist_info{
                leader_scene_id = Scene, leader_x = X, leader_y = Y
            },
            NewTeamMaps = TeamMaps#{TeamId := TeamEnlistInfo2},
            change_team(T, TeamId, NewTeamMaps, ActivityMaps, NumMaps);
        _ -> change_team(T, TeamId, TeamMaps, ActivityMaps, NumMaps)
    end;
change_team([{password, Password}|T], TeamId, TeamMaps, ActivityMaps, NumMaps) ->
    case maps:get(TeamId, TeamMaps, 0) of
        0 -> change_team(T, TeamId, TeamMaps, ActivityMaps, NumMaps);
        TeamEnlistInfo ->
            NewTeamMaps = TeamMaps#{TeamId := TeamEnlistInfo#team_enlist_info{password = Password} },
            change_team(T, TeamId, NewTeamMaps, ActivityMaps, NumMaps)
    end;
change_team([], _TeamId, TeamMaps, ActivityMaps, NumMaps) -> {TeamMaps, ActivityMaps, NumMaps};
change_team([_|T], TeamId, TeamMaps, ActivityMaps, NumMaps) -> change_team(T, TeamId, TeamMaps, ActivityMaps, NumMaps).

match_team_request(MatchRolesMap, MatchRole, Mb, TeamMaps) ->
    case MatchRole of
        #matching_role{waiting_team_ids = [TeamId|T], ref = Ref, role_id = RoleId} ->
            case check_match(TeamId, TeamMaps, MatchRole) of
                true ->
                    mod_team:cast_to_team(TeamId,  {'match_team_request', Mb, Ref}),
                    MatchRolesMap#{RoleId => MatchRole#matching_role{waiting_team_ids = T}};
                _ ->
                    match_team_request(MatchRolesMap, MatchRole#matching_role{waiting_team_ids = T}, Mb, TeamMaps)
            end;
        #matching_role{role_id = RoleId, node = Node, waiting_team_ids = [], activity_list = [{ActId, SubId}|_]} ->
            lib_player:apply_cast(Node, RoleId, ?APPLY_CAST_STATUS, ?NOT_HAND_OFFLINE, lib_team, handle_noteam_for_match, [ActId, SubId]),
            maps:remove(RoleId, MatchRolesMap);
        _ ->
            MatchRolesMap
    end.

check_match(TeamId, TeamMaps, #matching_role{activity_list = ActivityList, lv = Lv, power = Power}) ->
    case maps:get(TeamId, TeamMaps, false) of
        #team_enlist_info{num=Num, matching = 1, leader_figure = #figure{lv = LeaderLv},
            activity_id = ActivityId, subtype_id = SubTypeId, lv_limit_min = LvMin,
            lv_limit_max = LvMax, max_num = NumMax, power_limit = PowerLimit, password = Password
        } when Num < NumMax ->
            if
                Lv < LvMin orelse Lv > LvMax -> false;
                ActivityList =:= [] -> true;
                true ->
                    case lists:member({ActivityId, SubTypeId}, ActivityList) of
                        false ->
                            false;
                        true  ->
                            case data_team_ui:get(ActivityId, SubTypeId) of
                                #team_enlist_cfg{dun_id = DunId} ->
                                    case data_dungeon:get_dun(DunId) of
                                        #dun_cfg{type = ?DUNGEON_TYPE_EXP} ->
                                            erlang:abs(Lv - LeaderLv) =< 10;
                                        #dun_cfg{type = ?DUNGEON_TYPE_TOWER} ->
                                            case lib_team_api:need_check_password(Password) of
                                                true ->
                                                    false;
                                                _ ->
                                                    Power >= PowerLimit
                                            end;
                                        _ ->
                                            true
                                    end;
                                _ -> %% 无相关配置
                                    false
                            end
                    end
            end;
        _ ->
            false
            % mod_team:cast_to_team(TeamId,  {'join_team_request', Mb})
    end.

update_match_roles(KeyValues, TeamId, TeamMaps, MatchRolesMap) ->
    case is_need_update_match(KeyValues) of
        true ->
            F = fun
                (_, MatchRole) ->
                    do_update_match_role(MatchRole, TeamId, TeamMaps)
            end,
            maps:map(F, MatchRolesMap);
        _ ->
            MatchRolesMap
    end.

is_need_update_match([{enlist, _, _}|_]) ->
    true;

is_need_update_match([{lv, _, _}|_]) ->
    true;

is_need_update_match([{matching, 1}|_]) ->
    true;

is_need_update_match([_|T]) ->
    is_need_update_match(T);

is_need_update_match([]) -> false.


do_update_match_role(MatchRole, TeamId, TeamMaps) ->
    #matching_role{waiting_team_ids = WaitingIds, role_id = RoleId, ref = Ref, node = Node} = MatchRole,
    case lists:member(TeamId, WaitingIds) of
        false ->
            case check_match(TeamId, TeamMaps, MatchRole) of
                true ->
                    NewRef = if
                        WaitingIds =:= [] ->
                            Ref2 = Ref + 1,
                            lib_player:apply_cast(Node, RoleId, ?APPLY_CAST_STATUS, ?NOT_HAND_OFFLINE, lib_team, auto_match_team, [[node(), Ref2]]);
                        true ->
                            Ref
                    end,
                    MatchRole#matching_role{waiting_team_ids = [TeamId|WaitingIds], ref = NewRef};
                _ ->
                    MatchRole
            end;
        _ ->
            MatchRole
    end.

fill_team_info_args(Info0, [{lv, Min, Max}|T]) ->
    Info = Info0#team_enlist_info{lv_limit_min = Min, lv_limit_max = Max},
    fill_team_info_args(Info, T);

fill_team_info_args(Info0, [{task,IsTask}|T]) ->
    Info = Info0#team_enlist_info{is_task=IsTask},
    fill_team_info_args(Info, T);

fill_team_info_args(Info0, [{online_flag, OnlineFlag}|T]) ->
    Info = Info0#team_enlist_info{leader_online = OnlineFlag},
    fill_team_info_args(Info, T);

fill_team_info_args(Info0, [{set_help_type, HelpType}|T]) ->
    Info = Info0#team_enlist_info{leader_help_type = HelpType},
    fill_team_info_args(Info, T);

fill_team_info_args(Info0, [{dungeon_count, DungeonCount}|T]) ->
    Info = Info0#team_enlist_info{dungeon_count = DungeonCount},
    fill_team_info_args(Info, T);

fill_team_info_args(Info0, [{server_num, ServerNum}|T]) ->
    Info = Info0#team_enlist_info{leader_server = ServerNum},
    fill_team_info_args(Info, T);

fill_team_info_args(Info0, [{server_id, ServerId}|T]) ->
    Info = Info0#team_enlist_info{leader_server_id = ServerId},
    fill_team_info_args(Info, T);

fill_team_info_args(Info0, [{chat_zone, ChatZone} | T]) ->
    Info = Info0#team_enlist_info{leader_chat_zone = ChatZone},
    fill_team_info_args(Info, T);

fill_team_info_args(Info0, [{srv_open_time, SrvOpenTime} | T]) ->
    Info = Info0#team_enlist_info{leader_srv_open_time = SrvOpenTime},
    fill_team_info_args(Info, T);

fill_team_info_args(Info0, [{leader_scene_id, Scene}|T]) ->
    Info = Info0#team_enlist_info{leader_scene_id = Scene},
    fill_team_info_args(Info, T);
fill_team_info_args(Info0, [{leader_scene_pool_id, _ScenePoolId}|T]) ->
    Info = Info0,
    fill_team_info_args(Info, T);
fill_team_info_args(Info0, [{leader_x, X}|T]) ->
    Info = Info0#team_enlist_info{leader_x = X},
    fill_team_info_args(Info, T);
fill_team_info_args(Info0, [{leader_y, Y}|T]) ->
    Info = Info0#team_enlist_info{leader_y = Y},
    fill_team_info_args(Info, T);
fill_team_info_args(Info0, [{password, Password}|T]) ->
    Info = Info0#team_enlist_info{password = Password},
    fill_team_info_args(Info, T);
fill_team_info_args(Info, []) -> Info;

fill_team_info_args(Info, [_|T]) ->
    fill_team_info_args(Info, T).



change_role_helper(MatchRole, []) -> MatchRole;
change_role_helper(MatchRole, [{lv, Lv}|T]) ->
    NewMatchRole = MatchRole#matching_role{lv = Lv},
    change_role_helper(NewMatchRole, T);
change_role_helper(MatchRole, [{power, Power}|T]) ->
    NewMatchRole = MatchRole#matching_role{power = Power},
    change_role_helper(NewMatchRole, T);
change_role_helper(MatchRole, [_|T]) ->
    change_role_helper(MatchRole, T).
