%% ---------------------------------------
%% desc     :离线托管-跨服团战
%% module   :offline_hosting_camp_war.erl
%% author   :hh
%% time     :20/08/01
%% ---------------------------------------

-module(offline_hosting_camp_war).

-export([
    host_behavior/3
    ]).

-include("server.hrl").
-include("camp_war.hrl").
-include("predefine.hrl").
-include("def_module.hrl").
-include("common.hrl").
-include("offline_hosting.hrl").
-include("attr.hrl").
-include("errcode.hrl").
-include("figure.hrl").

-compile([export_all]).

%% 开启离线托管
% #{arena_id => [{guild_id, server_id}]}
camp_war_offline_hosting(ClsType, ArenaMap) ->
    ArenaGuildList = get_serv_guild(ArenaMap),
    % ?ERR("~p", [ArenaGuildList]),
    Pid = spawn(fun() -> 
        timer:sleep(30000),
        camp_war_offline_hosting_do(ClsType, ArenaGuildList, 1)
    end),
    Pid.

camp_war_offline_hosting_do(_, [], _) ->
    ok;
camp_war_offline_hosting_do(_, _ArenaGuildList, Num) when Num >= 55 ->
    ok;
camp_war_offline_hosting_do(ClsType, ArenaGuildList, Num) ->
    camp_war_offline_hosting_logic(ClsType, ArenaGuildList),
    timer:sleep(5000),
    camp_war_offline_hosting_do(ClsType, ArenaGuildList, Num+1).

camp_war_offline_hosting_logic(_, []) ->
    ok;
camp_war_offline_hosting_logic(ClsType, [{_ArenaId, ServGuildL}|Rest]) ->
    Len = length(ServGuildL),
    RandLen = urand:rand(1, Len),
    RandGuildL = urand:get_rand_list(RandLen, ServGuildL),
    RandGuildNumL = calc_guild_rand_role_num(RandGuildL, 10, []),
    % ?ERR("~p", [RandGuildNumL]),
    tagrget_guild_offline_hosting(ClsType, RandGuildNumL),
    camp_war_offline_hosting_logic(ClsType, Rest).


calc_guild_rand_role_num([], _, Acc) -> Acc;
calc_guild_rand_role_num(_GuildL, 0, Acc) -> Acc;
calc_guild_rand_role_num([{ServId, ServGuildL}|Rest], Count, Acc) ->
    {NewCount, NewAcc} = calc_guild_rand_role_num_do(ServId, ServGuildL, Count, Acc),
    if NewCount =< 0 ->
            NewAcc;
        true ->
            calc_guild_rand_role_num(Rest, NewCount, NewAcc)
    end.

calc_guild_rand_role_num_do(_, [], Count, Acc) -> {Count, Acc};
calc_guild_rand_role_num_do(_ServId, _GuildL, Count, Acc) when Count =< 0 ->
    {Count, Acc};
calc_guild_rand_role_num_do(ServId, [GuildId|Rest], Count, Acc) ->
    RandCount = urand:rand(1, Count),
    if RandCount == 0 ->
            {RandCount, Acc};
        true ->
            NewCount = Count - RandCount,
            calc_guild_rand_role_num_do(ServId, Rest, NewCount, [{ServId, GuildId, RandCount}|Acc])           
    end.


get_serv_guild(ArenaMap) ->
    lists:foldl(fun({ArenaId, GuildList}, Acc) -> 
        NewTempServGuildL = lists:foldl(fun({GuildId, ServId}, TempServGuildL) -> 
            case lists:keyfind(ServId, 1, TempServGuildL) of
                {_, ServGuildL} ->
                    NewServGuildL =
                     case lists:member(GuildId, ServGuildL) of
                        true ->
                            ServGuildL;
                        _ ->
                            [GuildId|ServGuildL]
                    end,
                    lists:keystore(ServId, 1, TempServGuildL, {ServId, NewServGuildL});
                _ ->
                    lists:keystore(ServId, 1, TempServGuildL, {ServId, [GuildId]})
            end
        end, [], GuildList),
        [{ArenaId, NewTempServGuildL}|Acc]
    end, [], maps:to_list(ArenaMap)).


tagrget_guild_offline_hosting(_, []) ->
    ok;
tagrget_guild_offline_hosting(ClsType, [{ServId, GuildId, Num}|Rest]) ->
    if ClsType == ?NODE_CENTER ->
            clusters_center:apply_cast(ServId, ?MODULE, guild_camp_war_off_hosting, [GuildId, Num]);
        true ->
            guild_camp_war_off_hosting(GuildId, Num)
    end,
    tagrget_guild_offline_hosting(ClsType, Rest).

%% 社团托管
guild_camp_war_off_hosting(GuildId, Num) ->
    mod_guild:apply_cast(?MODULE, guild_camp_war_off_hosting_do, [GuildId, Num]).

guild_camp_war_off_hosting_do(GuildId, Num) ->
    GuildMember = lib_guild_data:get_guild_member_map(GuildId),
    MemberIds = maps:keys(GuildMember),
    % ?ERR("~p ~p", [GuildId, MemberIds]),
    do_camp_war_off_hosting(GuildId, MemberIds, Num).

do_camp_war_off_hosting(_, [], _) ->
    ok;
do_camp_war_off_hosting(_, _, Num) when Num =< 0 ->
    ok;
do_camp_war_off_hosting(GuildId, [RoleId|Rest], Num) ->
    case ets:lookup(?ETS_HOSTING_ROLE, RoleId) of
        [#ets_hosting_role{}|_] ->
            do_camp_war_off_hosting(GuildId, Rest, Num);
        _ ->
            Res = offline_hosting:take_part_in(?MODULE, ?MOD_CAMP_WAR, RoleId, []),
            case Res of
                1  ->
                    do_camp_war_off_hosting(GuildId, Rest, Num-1);
                _A  -> %% ?ERR("~p ~p", [_A, RoleId]),
                    do_camp_war_off_hosting(GuildId, Rest, Num)
            end
    end.




%% 托管行为-上线
host_behavior(login, Player, _) ->
    %% 进入团战场景
    pp_camp_war:handle(41002, Player, [0]),
    {ok, Player};

host_behavior('MOVE', Player, _) ->
    role_go_move_do(Player);

%% 死亡行为
host_behavior(die, Player, _) ->
    {ok, Player1} = offline_hosting:host_behavior_delay(Player, revive, [], 10000),
    {ok, Player1};

%% 复活行为
host_behavior(revive, Player, _) ->
    #player_status{battle_attr = #battle_attr{hp_lim = HpLim} = BA, scene = Scene, scene_pool_id = ScenePool} = Player,
    %% 安全区复活,离开场景
    mod_scene_agent:leave(Player),
    BornList = data_camp_war:get_kv(born_position),
    {X, Y} = urand:list_rand(BornList),
    NewPlayer = Player#player_status{battle_attr = BA#battle_attr{hp = HpLim}, x = X, y = Y},
    %% 加载场景
    {ok, NewPlayer1} = pp_scene:handle(12002, NewPlayer, []),
    [{TarX, TarY}|_] = data_camp_war:get_kv(boss_position),
    DestinationBehavior = 'CAMP_WAR_ATTACK',
    %% 默认
    BossId = 0,
    offline_hosting:host_behavior_move(NewPlayer1, TarX, TarY, DestinationBehavior, [Scene, ScenePool, BossId], 10000);

%% 托管结束处理
host_behavior(host_end, NewPlayer, _Arg) ->
    #player_status{id = RoleId, figure = #figure{guild_id = GuildId}, online = Online, reconnect = Reconnect, action_lock = ActionLock} = NewPlayer,
    if
        Online == ?ONLINE_OFF_HOSTING andalso Reconnect == ?RE_LOGIN -> %% 玩家上线结束托管
            Errcode = ?ERRCODE(err410_on_camp_war),
            if ActionLock == Errcode ->
                    ServerId = config:get_server_id(),
                    camp_war_api:relogin(ServerId, GuildId, RoleId);
                true -> %% 不处于团战
                    skip
            end;
        true -> %% 正常结束
            skip
    end,
    {ok, NewPlayer};

%% 自定义行为
host_behavior('CAMP_WAR_ATTACK', Player, [_Scene, _ScenePool, _BossId|_]) ->
    offline_hosting:host_behavior_battle(Player, 3),
    {ok, Player};

    

host_behavior(_Behavior, Player, _Any) ->
    % ?ERR("unexcept behavior:~p ~p", [Behavior, _Any]),
    {ok, Player}.

%% 团战进程通知托管玩家进入移动模式
notice_hosting_role_go_move(State) ->
    #zone_fac_state{role_rank = RoleRank, cls_type = ClsType} = State,
    lists:map(fun({_ArenaId, ArenaRoles}) ->
        lists:map(fun(Role) -> 
            #camp_war_role{
                role_id = RoleId, server_id = ServId, 
                is_host = IsHost, in_act = InAct
            } = Role,
            case IsHost == 1 andalso InAct == 1 of
                true ->
                    if ClsType == ?NODE_CENTER ->
                            clusters_center:apply_cast(ServId, ?MODULE, role_go_move, [RoleId]);
                        true ->
                            role_go_move(RoleId)
                    end;
                _ ->
                    skip
            end
        end, ArenaRoles) 
    end, RoleRank),
    State.

%% 团战进程通知托管玩家发起攻击
notice_hosting_role_go_attack(State) ->
    #zone_fac_state{role_rank = RoleRank, extra_map = Map, cls_type = ClsType} = State,
    BossList = maps:get(?BOSS_UNIQUE_ID, Map, []),
    lists:map(fun({_ArenaId, ArenaRoles}) ->
        lists:map(fun(Role) ->
            #camp_war_role{role_id = RoleId, server_id = ServId, is_host = IsHost, in_act = InAct} = Role, 
            case IsHost == 1 andalso InAct == 1 of
                true ->
                    if ClsType == ?NODE_CENTER ->
                            clusters_center:apply_cast(ServId, ?MODULE, role_go_attack, [RoleId, BossList]);
                        true ->
                            role_go_attack(RoleId, BossList)
                    end;
                _ ->
                    skip
            end
        end, ArenaRoles)
    end, RoleRank),
    ok.

role_go_move(RoleId) ->
    %% 托管玩家进程是否能进程cast
    lib_player:apply_cast(RoleId, ?APPLY_CAST_STATUS, ?MODULE, role_go_move_do, []).

role_go_move_do(Player) ->
    {TargetX, TargetY} = get_rand_coordinate(),
    % ?ERR("~p move", [Player#player_status.id]),
    %% 默认的move行为
    DestinationBehavior = 'MOVE',
    offline_hosting:host_behavior_move(Player, TargetX, TargetY, DestinationBehavior, [], 10000).

%% 先到目标坐标,再发起攻击
role_go_attack(RoleId, BossList) ->
    lib_player:apply_cast(RoleId, ?APPLY_CAST_STATUS, ?MODULE, role_go_attack_do, [BossList]).

role_go_attack_do(Player, BossList) ->
    #player_status{offline_hosting = OfflineHosting, scene = Scene, scene_pool_id = ScenePool} = Player,
    BossId = get_boss_id(BossList, ScenePool),
    #offline_hosting{behavior_ref = Ref} = OfflineHosting,
    util:cancel_timer(Ref),
    [{TarX, TarY}|_] = data_camp_war:get_kv(boss_position),
    DestinationBehavior = 'CAMP_WAR_ATTACK',
    offline_hosting:host_behavior_move(Player, TarX, TarY, DestinationBehavior, [Scene, ScenePool, BossId], 3000).

get_boss_id(BossList, ScenePool) ->
    case lists:keyfind(ScenePool, 1, BossList) of
        {_, BossId} -> BossId;
        _   -> 0
    end.

get_rand_coordinate() ->
    {BaseX, BaseY} = {5000, 4000},
    RandX = urand:rand(BaseX-400, BaseX+500),
    RandY = urand:rand(BaseY-700, BaseY+800),
    {RandX, RandY}.