%%%-------------------------------------------------------------------
%%% @doc     废土托管
%%% Module  : offline_hosting_wasteland_war.erl
%%% Created : 2020-08-06
%%% @Author : tyl
%%%-------------------------------------------------------------------
-module(offline_hosting_wasteland_war).

%% -callback
-export([
	host_behavior/3
]).

-compile(export_all).

-include("server.hrl").
-include("wasteland_war.hrl").
-include("predefine.hrl").
-include("def_module.hrl").
-include("common.hrl").
-include("offline_hosting.hrl").
-include("errcode.hrl").
-include("scene.hrl").
-include("figure.hrl").
-include("battle.hrl").
-include("attr.hrl").
-include("def_event.hrl").
-include("rec_event.hrl").
-include_lib("stdlib/include/ms_transform.hrl").

%% 获取设置了托管并且不在线的玩家,
%% 此处获取所有设置了托管的玩家,是否在线以及托管值是否足够等条件判断
%% 交给take_part_in
%% 活动开启10秒后,每2秒进入20个玩家
%% @param: return - Pid  返回托管管理进程Id
%% ---------------------------------- 准备阶段 -----------------------------------------
wasteland_war_hosting() ->
	% AllCanHostId = ets:match(?ETS_OFFLINE_HOSTING, #ets_offline_hosting{role_id = '$1', _ = '_'}),
	Fun = ets:fun2ms(fun(EtsHosting) when EtsHosting#ets_offline_hosting.value> 0 -> EtsHosting#ets_offline_hosting.role_id end),
	AllCanHostId = ets:select(?ETS_OFFLINE_HOSTING, Fun),
	Pid = spawn(
		fun() ->
			%% 根据zone_id个位数来决定睡眠时间
			case czone_api:zone_open_check() of
				{true, ZoneId} ->
					Num = ZoneId rem 10,
					SleepTime = Num * 1000;
				_ ->
					SleepTime = 1000
			end,
			timer:sleep(SleepTime),
			player_do_hosting(AllCanHostId, 0) end
	),
	Pid.

%% 每2秒进入20个玩家(只拿数据,不切换场景)
player_do_hosting([], Count) -> Count;
player_do_hosting([HostId|L], Count) ->
	lib_player:apply_cast(HostId, ?APPLY_CAST_STATUS, ?HAND_OFFLINE, ?MODULE, cast_host_info, []),
	NewCount = case Count =:= 20 of
		           true  ->
			           timer:sleep(2000),
			           0;
		           false ->
			           Count + 1
	           end,
	player_do_hosting(L, NewCount).

%% 将玩家数据保存在玩法进程,注意需要托管值>0 todo(注意托管玩家is_in_scene = 0)
cast_host_info(Player) ->
	#player_status{id = RoleId, figure = Figure, battle_attr = BattleAttr} = Player,
	%% 是否满足托管条件
	Res = offline_hosting:check_can_host(RoleId, ?MOD_WASTELAND_WAR, 1),
	Pid = misc:get_player_process(RoleId),
	case misc:is_process_alive(Pid) of
		%% 真实玩家忽略
		true -> ignore;
		_ ->
			case Res of
				{true, _, _} ->
					ServerId  = config:get_server_id(),
					ServerNum = config:get_server_num(),
					Node = clusters_node:get_node(),
					IsHosting = ?IN_HOSTING,
					% Args = [Node, RoleId, Figure, ServerId, ServerNum, IsHosting, BattleAttr#battle_attr.hp_lim],
					mod_wasteland_war:enter_scene(Node, RoleId, Figure, ServerId,
						ServerNum, IsHosting, BattleAttr#battle_attr.hp_lim
					);
				_ -> ignore
			end
	end.

%% 准备阶段创建假人(玩法进程消息驱动)
cast_create_dummy(_Node, ServerId, RoleId, SceneId, PoolId, X, Y) ->
	[{_, ReadyTime}, _] = data_wasteland_war:get_kv_cfg(stage_time),
	Args = #{
		scene_id => SceneId,
		scene_pool => PoolId,
		copy_id => 0,
		x => X,
		y => Y,
		init_args => [{server_id, ServerId}],
		mon_args => [{revive_time, 10*1000},{state, sleep}, {find_type, 1}, {tracing_distance, 2000},
			{offline_hosting, #offline_hosting_dummy{handler = ?MODULE, module_id = ?MOD_WASTELAND_WAR}},
			{delay_cost_value, (ReadyTime + 30)*1000} %% 这里再延迟30秒,避免change_scene回调和扣除回调写ets的时候前后不一致
		]
	},
	offline_hosting_dummy:take_part_in(?MODULE, ?MOD_WASTELAND_WAR, 1, RoleId, Args),
	ok.

%% 假人创建后记录数据到玩法进程(在怪物进程)
host_behavior(login, State, Arg) ->
	#ob_act{object = Object} = State,
	#scene_object{id = MonId, figure = Figure} = Object,
	case lists:keyfind(server_id, 1, Arg) of
		{server_id, ServerId} ->
			mod_wasteland_war:create_dummy(ServerId, Figure#figure.id, MonId);
		_ ->
			%% 找不到server? todo
			ignore
	end,
	{ok, State};

%% 切换场景后开始找人
%% (随机一个时间先冲刺到非安全区附近，复活不清空冲刺路径，遇到安全区可以继续使用这段路径，
%% 这样假人会逐渐集中在战场中心)
host_behavior(change_scene, State, _Args) ->
	#ob_act{object = SceneObject, general_driven = _DelayGeneralDriven} = State,
	#scene_object{battle_attr = BattleAttr, scene = SceneId, x = OX, y = OY
	} = SceneObject,
	#battle_attr{pk = PK, speed = Speed} = BattleAttr,
	PK1 = case is_record(PK, pk) of
		      true -> PK;
		      _ -> #pk{}
	      end,
	NowTime = utime:unixtime(),
	{TargetX, TargetY} = get_target_point(SceneId),
	NewPath = lib_scene_object_ai:dest_path(OX, OY, TargetX, TargetY, Speed),
	NewSceneObject = SceneObject#scene_object{battle_attr = BattleAttr#battle_attr{
		pk = PK1#pk{pk_protect_time = NowTime + 6}
	}},
	Time = urand:rand(6, 15),
	% mon_mgr:send_after(Time * 1000, Aid, MonId, rush_and_find_target),
	State1 = mon_state_util:update_general_driven(State, [{Time*1000, rush_and_find_target}]),
	{ok, State1#ob_act{find_type = 1, path= NewPath, object = NewSceneObject}};

%% 死亡之后计算积分
host_behavior(die, State, [KList, Atter]) ->
	%% 被杀假人记录死亡状态
	#ob_act{object = SceneObject} = State,
	#scene_object{scene = SceneId, dummy = Dummy, figure = #figure{id = BeKillId}} = SceneObject,
	#scene_dummy{node = Node, server_id = ServerId} = Dummy,
	mod_wasteland_war:record_die_state(Node, ServerId, BeKillId),
	%% 击杀者和助攻者增加积分
	#battle_return_atter{id = KillId} = Atter,
	KList1 = [{KId, Time}||#mon_atter{id = KId, time = Time}<-KList],
	%% todo:是否使用atter的srv_id
	mod_wasteland_war:kill_player(Node, SceneId, KillId, BeKillId, ServerId, KList1),
	{ok, State};

%% 复活重新分配坐标
host_behavior(revive, State, []) ->
	#ob_act{object = SceneObject, general_driven = _DelayGeneralDriven} = State,
	#scene_object{scene = SceneId, dummy = Dummy, figure = #figure{id = RoleId},
		battle_attr = BattleAttr} = SceneObject,
	#scene_dummy{node = Node, server_id = ServerId} = Dummy,
	{BornX, BornY} = lib_wasteland_war:get_war_pos(SceneId),
	%% 刷新死亡状态
	mod_wasteland_war:clean_die_state(Node, ServerId, RoleId),
	%% 给2s保护时间，因为复活3s后寻敌
	#battle_attr{pk = PK} = BattleAttr,
	PK1 = case is_record(PK, pk) of
		      true -> PK;
		      _ -> #pk{}
	      end,
	NowTime = utime:unixtime(),
	NewSceneObject = SceneObject#scene_object{x = BornX, y = BornY,
		battle_attr = BattleAttr#battle_attr{pk = PK1#pk{pk_protect_time = NowTime + 2}
	}},
	{ok, State#ob_act{object = NewSceneObject}};

%% 玩家重连处理
host_behavior(host_end_pre, Player, _) when is_record(Player, player_status) ->
	{ok, Player};

host_behavior(host_end, Player, _) when is_record(Player, player_status) ->
	{ok, Player};

%% 其他处理
host_behavior(_, Player, _) when is_record(Player, player_status) ->
	{ok, Player};
host_behavior(_, State, _) when is_record(State, ob_act) ->
	{ok, State}.

%% 托管玩家上线,修改玩法里的状态数据(销毁假人)
handle_event(Player = #player_status{server_id = ServerId, id = RoleId},
		#event_callback{type_id = ?EVENT_HOSTING_DUMMY_LOGIN, data = Mod}) ->
	case Mod of
		?MOD_WASTELAND_WAR ->
			Node = clusters_node:get_node(),
			mod_wasteland_war:host_login(Node, ServerId, RoleId);
		_ -> ignore
	end,
	if Mod == ?MOD_WASTELAND_WAR ->
			Player1 = lib_activity_reserve:trigger_reserve_act(Player, Mod);
		true ->
			Player1 = Player
	end,
	{ok, Player1};
handle_event(Player, #event_callback{}) ->
	{ok, Player}.

%% ---------------------------------- 战斗开始 -----------------------------------------
%% 假人退出场景
cast_dummy_out(RoleId) ->
	case offline_hosting_data:hosting_role_lookup(RoleId) of
		[#ets_hosting_role{
			mod = Mod,
			pid = MonPid,
			mon_id = MonId
		}] when Mod == ?MOD_WASTELAND_WAR, MonId > 0 ->
			offline_hosting_dummy:notice_logout(RoleId, MonPid, MonId);
		_ ->
			ignore
	end.

%% 获取假人冲刺的坐标
get_target_point(SceneId) ->
	case data_wasteland_war:get_pos_list(SceneId) of
		#wasteland_select_pos_cfg{pos_list = PosList} ->
			NewPosList =
				case PosList of
					[{_, _, _}|_] -> [{X, Y}||{X, Y, _R}<-PosList];
					[{_, _}|_] -> PosList;
					_ -> [{2945,3559}]
				end,
			{CenterX, CenterY} = urand:list_rand(NewPosList),
			%% 中心点200像素范围内
			{TargetX, TargetY} = umath:rand_point_in_circle(CenterX, CenterY, 200, 1),
			{TargetX, TargetY} ;
		_ ->
			{2945,3559}
	end.

%% --------------------------------------------------------------------------------------
%% @doc 以下均为旧的托管逻辑 @end
%% --------------------------------------------------------------------------------------
%% 活动结束
%%act_end() ->
%%	%AllHostId = ets:match(?ETS_OFFLINE_HOSTING, #ets_offline_hosting{role_id = '$1', _ = '_'}),
%%	%F = fun(HostId) ->
%%	%	lib_player:apply_cast(HostId, ?APPLY_CAST_STATUS, ?MODULE, leave_wasteland_scene, [])
%%	%    end,
%%	%lists:foreach(F, lists:flatten(AllHostId)),
%%	offline_hosting:notice_logout(?MOD_WASTELAND_WAR).

%%leave_wasteland_scene(Player) ->
%%	#player_status{id = RoleId, offline_hosting = OffLineHosting} = Player,
%%	#offline_hosting{handler = Handler, behavior_ref = Ref} = OffLineHosting,
%%	case Handler == offline_hosting_wasteland_war of
%%		true ->
%%			util:cancel_timer(Ref),
%%			Node = clusters_node:get_node(),
%%			%% 退出场景
%%			Args = [RoleId, 0, 0, 0, []],
%%			lib_wasteland_war:switch_scene_callback(Node, Args);
%%		_ ->
%%			ignore
%%	end,
%%	{ok, Player}.
%%
%%%% 托管行为 - 上线进入场景
%%host_behavior(login, Player, _) ->
%%	%% 进入场景,会根据本服的情况决定进入本服还是跨服废土战场
%%	pp_wasteland_war:handle(60201, Player, []),
%%	{ok, Player1} = offline_hosting:host_behavior_delay(Player, load_scene, [], 5000), %% 此处需等待 change_scene 返回
%%	{ok, Player1};
%%
%%%% 托管行为 - 加载场景(托管玩家加载到场景)
%%host_behavior(load_scene, Player, _) ->
%%	#player_status{scene = SceneId} = Player,
%%	%% 加载场景
%%	{ok, Player1} = pp_scene:handle(12002, Player, []),
%%	%% 一秒后开始战斗
%%	ClsScenes   = data_wasteland_war:get_cls_all_scene(),
%%	LocalScenes = data_wasteland_war:get_all_scene(),
%%	case lists:member(SceneId, ClsScenes ++ LocalScenes) of
%%		true ->
%%			{ok, Player2} = offline_hosting:host_behavior_delay(Player1, battle, [], 1000);
%%		_ ->
%%			Player2 = Player1
%%	end,
%%	{ok, Player2};
%%
%%%% 托管行为 - 开始战斗
%%host_behavior(battle, Player, _) ->
%%	%% 优先攻击人
%%	{ok, Player1} = offline_hosting:host_behavior_battle(Player, 2),
%%	{ok, Player1};
%%
%%%% 托管行为 - 玩家死亡
%%host_behavior(die, Player, _) ->
%%	#player_status{offline_hosting = OffLineHosting} = Player,
%%	#offline_hosting{handler = Handler} = OffLineHosting,
%%	case Handler == offline_hosting_wasteland_war of
%%		true -> {ok, Player1} = offline_hosting:host_behavior_delay(Player, delay_revive, [], (?WASTELAND_REVIVE_CD+1) * 1000); %% CD过后1s复活,防止CD还未清除
%%		_    ->  Player1 = Player
%%	end,
%%	{ok, Player1};
%%
%%host_behavior(delay_revive, Player, _) ->
%%	#player_status{offline_hosting = OffLineHosting} = Player,
%%	#offline_hosting{handler = Handler} = OffLineHosting,
%%	case Handler == offline_hosting_wasteland_war of
%%		true ->
%%			%% 原地满血复活
%%			{_Result, Player1} = lib_revive:revive(Player, 5);
%%		_    ->
%%			Player1 = Player
%%	end,
%%	{ok, Player1};
%%
%%host_behavior(host_end, Player, _) ->
%%	{ok, Player};
%%host_behavior(host_end_pre, Player, _) ->
%%	{ok, Player}.
%%
%%%% 切换到下一轮场景
%%cast_load_scene_behavior(RoleId) ->
%%	lib_player:apply_cast(RoleId, ?APPLY_CAST_STATUS, ?MODULE, load_scene_behavior, []).
%%
%%load_scene_behavior(Player) ->
%%	#player_status{offline_hosting = OffLineHosting} = Player,
%%	#offline_hosting{handler = Handler} = OffLineHosting,
%%	case Handler == offline_hosting_wasteland_war of
%%		true -> {ok, Player1} = offline_hosting:host_behavior_delay(Player, load_scene, [], 10000); %% 10秒后加载到场景,等待切换场景回调
%%		_    ->  Player1 = Player
%%	end,
%%	{ok, Player1}.

%% 复活事件回调
%%handle_event(Player, #event_callback{type_id = ?EVENT_REVIVE}) ->
%%	{ok, Player1} = offline_hosting:host_behavior_delay(Player, battle, [], 1000),
%%	{ok, Player1}.