%%%-------------------------------------------------------------------
%%% @doc 境界学位--任务触发
%%% Module: lib_degree.erl
%%% Created : 2019-11-25
%%% @Author: tyl
%%%-------------------------------------------------------------------
-module(lib_degree_task).

-include("common.hrl").
-include("server.hrl").
-include("degree.hrl").
-include("figure.hrl").
-include("predefine.hrl").
-include("errcode.hrl").
-include("def_module.hrl").
-include("scene.hrl").

-export([
	finish_dun/3,                   %% 副本通关
	finish_kill_mon/1,              %% 击杀怪物
	finish_upgrade_mount/3          %% 坐骑升星
]).

-compile(export_all).

%% ------------------------------- API -------------------------------
%% 完成副本 % 副本进程/玩家进程调用
finish_dun(Player, DunId, Num) ->
	UpgradeDunList = data_degree:get_all_upgrade_dun(),    %% 晋升学位通关副本
	case lists:member(DunId, UpgradeDunList--[0]) of
		true ->
			{ok, NewPlayer} = trigger_upgrade_task(finish_dun, Player, DunId, Num);
		_ ->
			{ok, NewPlayer} = trigger_classwork_task(finish_dun, Player, DunId, Num)
	end,
	NewPlayer.

%% 杀怪,组队刷怪 % lib_mon_event:be_killed()中调用
finish_kill_mon({kill_mon, MonId, Num, BeLongWhos}) when is_list(BeLongWhos) ->
	F = fun(Atter, TList) ->
		case Atter of
			#mon_atter{node = Node, id = RoleId} ->
				[{Node, RoleId}| TList];
			_ -> TList
		end
	    end,
	PlayerArgsList = lists:foldl(F, [], BeLongWhos),
	trigger_classwork_task(kill_mon, PlayerArgsList, MonId, Num);
%% 杀怪,单人刷怪
finish_kill_mon({kill_mon, MonId, Num, RoleId}) when is_integer(RoleId) ->
	trigger_classwork_task(RoleId, {?ClassWorkKillMon, MonId}, Num).

%% 坐骑升星
finish_upgrade_mount(Player, MountId, Star) ->
	trigger_classwork_task(upgrade_mount, Player, MountId, Star).


%% ------------------------------- builtin function -------------------------------
%% 1.晋升任务
trigger_upgrade_task(finish_dun, Player, DunId, Num) ->
	trigger_task(Player, ?FIN_DEGREE_UPGRADE_DUN, 0, DunId, Num).

%% 2.日常功课任务
%% 场景怪物进程调用,特殊处理
trigger_classwork_task(kill_mon, RoleArgsList, Id, Num) when is_list(RoleArgsList) ->
	IsCls = util:is_cls(),
	case IsCls of
		true ->
			F = fun({Node, RoleId}, TMap) ->
				case maps:get(Node, TMap, []) of
					[_|_] = TList -> maps:put(Node, [RoleId|TList], TMap);
					_ -> TMap
				end
			    end,
			NodeMap = lists:foldl(F, #{}, RoleArgsList),  %% 按node分类
			F1 = fun(Node, PlayerList, Ack) ->
				clusters_center:apply_cast(Node, ?MODULE, trigger_classwork_task,
					[PlayerList, {?ClassWorkKillMon, Id}, Num]),
				Ack
				end,
			maps:fold(F1, true, NodeMap);
		false ->
			PlayerList = [RoleId||{_Node, RoleId} <- RoleArgsList],
			trigger_classwork_task(PlayerList, {?ClassWorkKillMon, Id}, Num)
	end;
%% 玩家进程调用,特殊处理
trigger_classwork_task(finish_dun, Player, DunId, Num) ->
	trigger_task(Player, ?ADD_CLASSWORK_PROGRESS, ?ClassWorkDun, DunId, Num);
trigger_classwork_task(upgrade_mount, Player, MountId, Stage) ->
	trigger_task(Player, ?ADD_CLASSWORK_PROGRESS, ?ClassworkMountUp, MountId, Stage).

%% 本服进程调用,通用
trigger_classwork_task(RoleIdList, Task, Num) when is_list(RoleIdList) ->
	{TaskType, TaskId} = Task,
	[lib_player:apply_cast(RoleId, ?APPLY_CAST_SAVE, ?MODULE, trigger_task, [?ADD_CLASSWORK_PROGRESS, TaskType, TaskId, Num])
		|| RoleId <- RoleIdList
	];
trigger_classwork_task(RoleId, Task, Num) when is_integer(RoleId) ->
	{TaskType, TaskId} = Task,
	IsCls = util:is_cls(),
	case IsCls of
		true ->     %% 跨服玩法
			Node = clusters_center:get_node_by_role_id(RoleId),
			clusters_center:apply_cast(Node, ?MODULE, trigger_classwork_task, [[RoleId], Task, Num]);
		_ ->
			lib_player:apply_cast(RoleId, ?APPLY_CAST_SAVE, ?MODULE, trigger_task, [?ADD_CLASSWORK_PROGRESS, TaskType, TaskId, Num])
	end.

trigger_task(Player, TriggerType, TaskType, Id, Num) ->
	#player_status{degree = Degree} = Player,
	#degree{daily_class = DailyClasses, dun_state = DunState} = Degree,
	#daily_class{
		class_progress_map = ClassProgressMap,
		class_status_map   = ClassStatusMap
	} = DailyClasses,
	UpgradeDunList = data_degree:get_all_upgrade_dun(),    %% 晋升学位通关副本
	case lists:member(Id, UpgradeDunList--[0]) andalso TriggerType == ?FIN_DEGREE_UPGRADE_DUN of
		true ->
			case DunState of
				[{Id, State}] when State == 1 ->
					has_finish(Player);
				[{Id, _State}] ->
					event(TriggerType, Player, Id, Num);
				_ -> no_match(Player)
			end;
		_ ->
			case match_classwork_from_daily_task(ClassProgressMap, Id, TaskType) of
				[DailyClassId|_] ->
					case maps:get(DailyClassId, ClassStatusMap, 0) of
						Status when Status >= ?ClassUnReceive -> has_finish(Player);
						_ -> event(TriggerType, Player, DailyClassId, Num)
					end;
				_ -> no_match(Player)
			end
	end.

event(_TriggerType = ?FIN_DEGREE_UPGRADE_DUN, Player, DunId, Num) ->
	NewPlayer = refresh_dun_state(Player, DunId, Num),
	CallBack = {ok, NewPlayer},
	CallBack;

event(_TriggerType = ?ADD_CLASSWORK_PROGRESS, Player, DailyClassId, Num) ->
	DailyClasses = lib_degree:get_dict_degree_classwork(Player),
	NewPlayer = refresh_daily_task(Player, DailyClasses, DailyClassId, Num),
	CallBack = {ok, NewPlayer},
	CallBack.

has_finish(Player) ->
	CallBack = {ok, Player},
	CallBack.

no_match(Player) ->
	CallBack = {ok, Player},
	CallBack.

%% TaskId ==> DailyClassWorkId,根据TaskId寻找对应的ClassId
match_classwork_from_daily_task(ClassProgressMap, Id, TaskType) ->
%%	ClassWorks = maps:keys(ClassProgressMap),
	F = fun(ClassWorkId, ClassWorkContent, ClassWorkList) ->
		case ClassWorkContent of
			[_|_]  ->
				[TargetType, TargetId, _Num] = ClassWorkContent,
				if
					TargetId == Id andalso TargetType == TaskType ->
						[ClassWorkId|ClassWorkList];
					true -> ClassWorkList
				end;
			_ -> ClassWorkList
		end
	end,
	NewClassWorkList = maps:fold(F, [], ClassProgressMap),
	NewClassWorkList.

%% 更新学位晋升副本状态
refresh_dun_state(Player, DunId, _Num) ->
	#player_status{degree = Degree, id = RoleId, sid = Sid} = Player,
	#degree{dun_state = DunState, degree_id = DegreeId} = Degree,
	DunConfig = data_degree:get_degree_cfg(DegreeId+1),
	TDunId =
	case DunConfig of
		[] ->   %% 满级了
			TDunConfig = data_degree:get_degree_cfg(DegreeId),
			#degree_cfg{finish_dungeon = NDunId}= TDunConfig,
			NDunId;
		_ ->
			#degree_cfg{finish_dungeon = NDunId}= DunConfig,
			NDunId
	end,
	case DunState of     %% 修正数据
		[{DunId, _State}|_] ->
			case DunId == TDunId of
				true -> NewDunState = [{DunId, 1}];
				_ ->    NewDunState = DunState
			end;
		[{0, _State}] ->
			NewDunState = [{TDunId, 0}];
		_ ->
			NewDunState = DunState
	end,
	NewDegree = Degree#degree{dun_state = NewDunState},
	%% 刷新前端数据
	StatusList = [?RefreshType1, DegreeId, 1, 0],
	{ok, Bin} = pt_166:write(16604, StatusList),
	lib_server_send:send_to_sid(Sid, Bin),
	lib_degree:update_db_degree_dun_state(RoleId, util:term_to_string(NewDunState)),
	lib_degree:save_dict_degree(Player, NewDegree).

%% 更新任务数据(内存数据肯定有该任务Id)
refresh_daily_task(Player, DailyClasses, DailyClassId, Num) ->
	#daily_class{
		class_status_map   = ClassStatusMap,
		class_progress_map = ClassProgressMap
	} = DailyClasses,
	#degree_timetable_cfg{target = [{Type, TargetId, NeedNum}]}
		= data_degree:get_degree_timetable_cfg(DailyClassId),
	[ClassType, _Id, OldNum] = maps:get(DailyClassId, ClassProgressMap),
	if
		ClassType == ?ClassWorkDun orelse ClassType == ?ClassWorkKillMon orelse ClassType == ?ClassworkMountUp ->
			NewNum = OldNum + Num,
			case NewNum >= NeedNum of
				true ->
					NewClassStatusMap   = maps:put(DailyClassId, ?ClassUnReceive, ClassStatusMap),
					NewClassProgressMap = maps:put(DailyClassId, [Type, TargetId, min(NewNum, NeedNum)], ClassProgressMap);
				false ->
					NewClassStatusMap   = ClassStatusMap,
					NewClassProgressMap = maps:put(DailyClassId, [Type, TargetId, NewNum], ClassProgressMap)
			end;
		true -> %% 留一个接口,计算方法不同(非累加)
			NewClassStatusMap   = ClassStatusMap,
			NewClassProgressMap = ClassProgressMap
	end,
	NewDailyClasses = DailyClasses#daily_class{
		class_status_map   = NewClassStatusMap,
		class_progress_map = NewClassProgressMap
	},
	NewPlayer = lib_degree:save_dict_degree_classwork(Player, NewDailyClasses),
	%% 数据库操作
	Progress = maps:get(DailyClassId, NewClassProgressMap),
	NewState = maps:get(DailyClassId, NewClassStatusMap),
	lib_degree:save_db_degree_classwork(Player#player_status.id, DailyClassId, make_content(Progress, NewState)),
	%% 刷新前端数据
	StatusList = [?RefreshType2, DailyClassId, min(OldNum + Num, NeedNum), NewState],
	{ok, Bin} = pt_166:write(16604, StatusList),
	lib_server_send:send_to_sid(Player#player_status.sid, Bin),
	NewPlayer.

make_content(ProgressList, State) ->
	[Type, TaskId, Num] = ProgressList,
	Content = [Type, TaskId, Num, State],
	Content.
