%%%-------------------------------------------------------------------
%%% @doc     功能预告
%%% Module  : lib_module_advance.erl
%%% Created : 2020-07-09
%%% @Author : tyl
%%%-------------------------------------------------------------------
-module(lib_module_advance).


-include("common.hrl").
-include("server.hrl").
-include("module_advance.hrl").
-include("figure.hrl").
-include("def_module.hrl").
-include("predefine.hrl").
-include("rec_event.hrl").
-include("def_event.hrl").
-include("errcode.hrl").

%% API
-export([
	login/2
	,handle_event/2
	,get_module_advance_state/1         %% 获取功能预告信息
	,get_module_advance_reward/2        %% 领取功能预告奖励
]).

%% 登录
login(RoleId, RoleLv) ->
	SQL = io_lib:format(?SQL_SELECT_ROLE_MODULE_ADVANCE, [RoleId]),
	case db:get_all(SQL) of
		Result = [_|_] ->
			RoleFuncs = init_data(Result),
			%% 检查是否有新增的功能Id
			case check_new_func(RoleFuncs) of
				NewFuncs = [_|_] ->
					%% 检查是否有新增满足要求的功能Id
					ActFuncs = check_funcs_active_state(RoleLv, NewFuncs, []),
					case ActFuncs of
						[_|_] ->
							db_update_change_data(RoleId, ActFuncs),
							lists:append(RoleFuncs, ActFuncs);
						_ ->
							RoleFuncs
					end;
				_ ->
					RoleFuncs
			end;
		_A -> %% 初始化
			AllFuncs = data_module_advance:get_all_module_ids(),
			RoleFuncs = check_funcs_active_state(RoleLv, AllFuncs, []),
			db_update_change_data(RoleId, RoleFuncs),
			RoleFuncs
	end.

%% 获取功能预告信息
get_module_advance_state(Player) ->
	#player_status{sid = Sid, module_advance = ModuleAdvance} = Player,
	{ok, Bin} = pt_182:write(18200, [ModuleAdvance]),
	lib_server_send:send_to_sid(Sid, Bin).

%% 领取功能预告奖励
get_module_advance_reward(FuncId, Player) ->
	#player_status{id = RoleId, sid = Sid, figure = #figure{lv = RoleLv}, module_advance = ModuleAdvance} = Player,
	OpenDay = util:get_open_day(),
	case lists:keyfind(FuncId, 1, ModuleAdvance) of
		{_, ?FUNC_REWARDING} ->
			case data_module_advance:get_module_advance_cfg(FuncId) of
				#base_module_advance{condition = [ConfigLv|_], reward = Reward, open_day = CfgOpenDay} when
					RoleLv >= ConfigLv andalso OpenDay >= CfgOpenDay->
					NewPlayer = lib_goods_api:send_reward(Player, Reward, module_advance_reward),
					NewModuleAdvance = lists:keyreplace(FuncId, 1, ModuleAdvance, {FuncId, ?FUNC_REWARDED}),
					db_update_role_module_advance(RoleId, FuncId, ?FUNC_REWARDED),
					add_log(RoleId, RoleLv, FuncId),
					{ok, Bin} = pt_182:write(18201, [?SUCCESS, FuncId, ?FUNC_REWARDED]),
					lib_server_send:send_to_sid(Sid, Bin),
					{ok, NewPlayer#player_status{module_advance = NewModuleAdvance}};
				_ ->
					{ok, Bin} = pt_182:write(18201, [?ERRCODE(err182_condition_not_met), FuncId, ?FUNC_REWARDING]),
					lib_server_send:send_to_sid(Sid, Bin)
			end;
		{_, ?FUNC_REWARDED} ->
			{ok, Bin} = pt_182:write(18201, [?ERRCODE(err182_reward_has_received), FuncId, ?FUNC_REWARDED]),
			lib_server_send:send_to_sid(Sid, Bin);
		_ ->
			{ok, Bin} = pt_182:write(18201, [?ERRCODE(err182_condition_not_met), FuncId, 0]),
			lib_server_send:send_to_sid(Sid, Bin)
	end.

%% 检查可以领取奖励的功能(不满足要求的不计算入内)
check_funcs_active_state(_, [], Acc) -> Acc;
check_funcs_active_state(RoleLv, [FuncId|Rest], Acc) ->
	case data_module_advance:get_module_advance_cfg(FuncId) of
		#base_module_advance{condition = [ConfigLv, TaskId]} ->
			if
				RoleLv >= ConfigLv ->
					if TaskId =:= 0 ->
							case check_func_open_day_limit(FuncId) of
								true ->
									check_funcs_active_state(RoleLv, Rest, [{FuncId, ?FUNC_REWARDING}|Acc]);
								_    ->
									check_funcs_active_state(RoleLv, Rest, Acc)
							end;
						true ->
							case lib_role_task:is_finish_task_id(TaskId) of
								true ->
									case check_func_open_day_limit(FuncId) of
										true ->
											check_funcs_active_state(RoleLv, Rest, [{FuncId, ?FUNC_REWARDING}|Acc]);
										_    ->
											check_funcs_active_state(RoleLv, Rest, Acc)
									end;
								_ ->
									check_funcs_active_state(RoleLv, Rest, Acc)
							end
					end;
				true ->
					check_funcs_active_state(RoleLv, Rest, Acc)
			end;
		_ ->
			check_funcs_active_state(RoleLv, Rest, Acc)
	end.

init_data(Data) ->
	[{FuncId, RewardState} || [FuncId, RewardState] <- Data].

check_new_func(RoleFuncs) ->
	AllFuncs = data_module_advance:get_all_module_ids(),
	lists:filter(fun(FuncId) ->
		case lists:keyfind(FuncId, 1, RoleFuncs) of
			{_, _} -> false;
			_      -> true
		end
	end, AllFuncs).

check_func_open_day_limit(FuncId) ->
	OpenDay = util:get_open_day(),
	case data_module_advance:get_module_advance_cfg(FuncId) of
		#base_module_advance{open_day = CfgOpenDay} ->
			if
				OpenDay >= CfgOpenDay ->
					true;
				true -> false
			end;
		_ ->
			false
	end.

handle_event(Player, #event_callback{type_id = ?EVENT_FINISH_TASK, data = TaskId}) ->
	#player_status{id = RoleId, module_advance = ModuleAdvance, figure = #figure{lv = RoleLv}} = Player,
	case data_module_advance:get_func_id_by_con(TaskId) of
		FuncIds = [_|_] ->
			FuncIds1 = filter_func(task, RoleLv, FuncIds),
			%% 协议推送
			PackList = pack_send(FuncIds1, []),
			PackList1 =
			lists:foldl(fun({TModuleId, TStatus}, TList)->
							case lists:keyfind(TModuleId, 1, ModuleAdvance) of
								{_, _} -> TList;
								_ -> [{TModuleId, TStatus}|TList]
							end
			end, [], PackList),
			PackList1 =/= [] andalso lib_server_send:send_to_uid(RoleId, pt_182, 18200, [ModuleAdvance++PackList1]),
			{NewModuleAdvance, ChangeData} = update_role_module_advance(FuncIds1, ModuleAdvance, []),
			ChangeData =/= [] andalso db_update_change_data(RoleId, ChangeData),
			{ok, Player#player_status{module_advance = NewModuleAdvance}};
		_ ->
			{ok, Player}
	end;
handle_event(Player, #event_callback{type_id = ?EVENT_LV_UP}) ->
	#player_status{id = RoleId, figure = #figure{lv = RoleLv}, module_advance = ModuleAdvance} = Player,
	case data_module_advance:get_func_id_by_con(RoleLv) of
		FuncIds = [_|_] ->
			FuncIds1 = filter_func(lv, RoleLv, FuncIds),
			%% 协议推送
			PackList = pack_send(FuncIds1, []),
			PackList1 =
			lists:foldl(fun({TModuleId, TStatus}, TList)->
			                case lists:keyfind(TModuleId, 1, ModuleAdvance) of
				                {_, _} -> TList;
								_ -> [{TModuleId, TStatus}|TList]
			                end
			            end, [], PackList),
			PackList1 =/= [] andalso lib_server_send:send_to_uid(RoleId, pt_182, 18200,  [ModuleAdvance++PackList1]),
			{NewModuleAdvance, ChangeData} = update_role_module_advance(FuncIds1, ModuleAdvance, []),
			ChangeData =/= [] andalso db_update_change_data(RoleId, ChangeData),
			{ok, Player#player_status{module_advance = NewModuleAdvance}};
		_ ->
			{ok, Player}
	end.

add_log(RoleId, RoleLv, FunId) ->
	OpenDay = util:get_open_day(),
	case data_module_advance:get_module_advance_cfg(FunId) of
		#base_module_advance{name = FunName, con_desc = ConDesc, reward = Reward} -> ok;
		_ -> FunName = "", ConDesc = "", Reward = []
	end,
	lib_log_api:log_advance_produce(RoleId, RoleLv, FunId, FunName, ConDesc, Reward, OpenDay),
	ok.

filter_func(lv, RoleLv, FuncIds) ->
	OpenDay = util:get_open_day(),
	lists:filter(fun(FuncId) ->
		case data_module_advance:get_module_advance_cfg(FuncId) of
			#base_module_advance{condition = [ConfigLv, TaskId], open_day = CfgOpenDay} ->
				if RoleLv >= ConfigLv ->
						case check_func_open_day_limit(FuncId) of
							true ->
								case TaskId == 0 of
									true -> true;
									_ ->
										case lib_role_task:is_finish_task_id(TaskId) of
											true when OpenDay >= CfgOpenDay -> true;
											_ -> false
										end
								end;
							_ -> false
						end;
					true  -> false
				end;
			_ ->
				false
		end end, FuncIds);
filter_func(task, RoleLv, FuncIds) ->
	OpenDay = util:get_open_day(),
	lists:filter(fun(FuncId) ->
		case data_module_advance:get_module_advance_cfg(FuncId) of
			#base_module_advance{condition = [ConfigLv, TaskId], open_day = CfgOpenDay} ->
				if TaskId =:= 0 ->
					check_func_open_day_limit(FuncId);
					true ->
						case lib_role_task:is_finish_task_id(TaskId) of
							true ->
								case check_func_open_day_limit(FuncId) of
									true ->
										case RoleLv >= ConfigLv of
											true when OpenDay >= CfgOpenDay -> true;
											_ -> false
										end;
									_ -> false
								end;
							_    ->
								false
						end
				end;
			_ ->
				false
		end end, FuncIds).

update_role_module_advance([], ModuleAdvance, Acc) -> {ModuleAdvance, Acc};
update_role_module_advance([FuncId|Rest], ModuleAdvance, Acc) ->
	case lists:keyfind(FuncId, 1, ModuleAdvance) of
		{_, _} ->
			update_role_module_advance(Rest, ModuleAdvance, Acc);
		_ ->
			NewModuleAdvance = lists:keystore(FuncId, 1, ModuleAdvance, {FuncId, ?FUNC_REWARDING}),
			update_role_module_advance(Rest, NewModuleAdvance, [{FuncId, ?FUNC_REWARDING}|Acc])
	end.

pack_send([], Pack) -> Pack;
pack_send([FuncId|L], TPack) ->
	pack_send(L, [{FuncId, ?FUNC_REWARDING}|TPack]).

tran_format([], SoFar) -> SoFar;
tran_format([[]], SoFar) -> SoFar;
tran_format([Data = [_RoleId, _FuncId, _FuncState]|Rest], SoFar) ->
	Value = io_lib:format(?SQL_ROLE_MODULE_ADVANCE_BATCH_VALUES, Data),
	tran_format(Rest, [Value|SoFar]).


%% ------------------------ db操作 --------------------------
db_update_role_module_advance(RoleId, FuncId, FuncState) ->
	SQL = io_lib:format(?SQL_REPLACE_ROLE_MODULE_ADVANCE, [RoleId, FuncId, FuncState]),
	db:execute(SQL).

db_update_change_data(RoleId, ChangeData) ->
	ChangeData1 = [[RoleId, FuncId, FuncState] || {FuncId, FuncState} <- ChangeData],
	SqlFormats = tran_format(ChangeData1, []),
	if SqlFormats =/= [] ->
		SqlFormats1 = util:join_bitstring(SqlFormats, <<", ">>),
		SqlFormats2 = unicode:characters_to_binary(io_lib:format(?SQL_ROLE_MODULE_ADVANCE_BATCH_REPLACE, [SqlFormats1])),
		db:execute(SqlFormats2);
		true ->
			ok
	end.