%%%-------------------------------------------------------------------
%%% @doc     藏宝图 - 高级藏宝图月度奖励管理进程
%%% Module  : mod_treasure_map_advance.erl
%%% Created : 2021-02-23
%%% @author : tyl
%%%-------------------------------------------------------------------
-module(mod_treasure_map_advance).

-include("common.hrl").
-include("server.hrl").
-include("figure.hrl").
-include("role.hrl").
-include("errcode.hrl").
-include("goods.hrl").
-include("def_module.hrl").
-include("def_goods.hrl").
-include("predefine.hrl").

-behaviour(gen_server).

%% API
-export([
	update_times/2              %% 更新玩家挖宝次数
	,monthly_reward/0           %% 月度结算玩家次数奖励
	,monthly_reward_info/1      %% 月度次数奖励信息
	,receive_monthly_reward/2   %% 领取月度次数奖励
]).

-export([start_link/0, cast/1 ,call/1 ,info/1]).

%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).


-record(treasure_map_state, {
	role_times  = []        %% 玩家挖宝次数[#role_times{},...]
}).

-record(role_times, {
	role_id        = 0
	,times         = 0        %% 挖宝次数
	,receive_times = []       %% 已经领取的次数[N,M...]
}).

%% 每月定时结算奖励
monthly_reward() ->
	cast({monthly_reward}).

update_times(RoleId, Times) ->
	cast({update_times, RoleId, Times}).

monthly_reward_info(RoleId) ->
	cast({monthly_reward_info, RoleId}).

receive_monthly_reward(RoleId, Times) ->
	cast({receive_monthly_reward, RoleId, Times}).

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

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

call(Msg) ->
	gen_server:call(?MODULE, Msg).

info(Msg) ->
	erlang:send(?MODULE, Msg).

init([]) ->
	process_flag(trap_exit, true),
	erlang:send_after(100, self(), {init_state}),
	{ok, #treasure_map_state{}}.

handle_call(Msg, From, State) ->
	try do_handle_call(Msg, From, State) of
		Reply ->
			Reply
	catch ?EXCEPTION(Class, Reason, StackTrace) ->
		Error = {Class, Reason, StackTrace},
		?ERR("~w:handle_call error:~p~n", [?MODULE, Error]),
		{error, Reason}
	end.

handle_cast(Msg, State) ->
	try do_handle_cast(Msg, State) of
		Result ->
			Result
	catch ?EXCEPTION(Class, Reason, StackTrace) ->
		Error = {Class, Reason, StackTrace},
		?ERR("~w:handle_cast error:~p~n", [?MODULE, Error]),
		{noreply, State}
	end.

handle_info(Info, State) ->
	try do_handle_info(Info, State) of
		Result ->
			Result
	catch ?EXCEPTION(Class, Reason, StackTrace) ->
		Error = {Class, Reason, StackTrace},
		?ERR("~w:handle_info error:~p~n", [?MODULE, Error]),
		{noreply, State}
	end.

terminate(_Reason, _State) ->
	ok.

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

%% ---------------------------------------------------------------------------
do_handle_call(_Msg, _From, State) ->
	{reply, ok, State}.

%% ---------------------------------------------------------------------------
do_handle_cast({monthly_reward_info, RoleId}, State) ->
	#treasure_map_state{role_times = RoleList} = State,
	case lists:keyfind(RoleId, #role_times.role_id, RoleList) of
		#role_times{receive_times = ReceiveList, times = Times} ->
			lib_server_send:send_to_uid(RoleId, pt_424, 42405, [Times, ReceiveList]);
		_ ->
			lib_server_send:send_to_uid(RoleId, pt_424, 42405, [0, []])
	end,
	{noreply, State};

do_handle_cast({receive_monthly_reward, RoleId, ReceiveTimes}, State) ->
	#treasure_map_state{role_times = RoleList} = State,
	TimeRewards = data_treasure_map:get_kv(advanced_map_times_reward),
	case TimeRewards of
		[{_, _, _}|_] ->
			case lists:keyfind(RoleId, #role_times.role_id, RoleList) of
				#role_times{receive_times = ReceiveList, times = Times} = RoleTimes ->
					case lists:member(ReceiveTimes, ReceiveList) of
						true ->
							lib_server_send:send_to_uid(RoleId, pt_424, 42406,
								[?ERRCODE(err424_reward_has_received), []]
							),
							NewState = State;
						_ ->
							case lists:keyfind(ReceiveTimes, 1, TimeRewards) of
								{_, RewardId, Num} ->
									Produce = #produce{
										type = treasure_map_monthly, reward = [{?TYPE_GOODS, RewardId, Num}]
									},
									lib_goods_api:send_reward_with_mail(RoleId, Produce, ?MOD_TREASURE_MAP),
									NewReceiveList = [ReceiveTimes|ReceiveList],
									NewRoleList = lists:keystore(RoleId, #role_times.role_id, RoleList,
										RoleTimes#role_times{receive_times = NewReceiveList}),
									lib_treasure_map_advance:db_save_monthly_times(RoleId, Times, NewReceiveList),
									lib_server_send:send_to_uid(RoleId, pt_424, 42406,
										[?SUCCESS, NewReceiveList]
									),
									NewState = State#treasure_map_state{role_times = NewRoleList};
								_ ->
									%% 配置错误
									lib_server_send:send_to_uid(RoleId, pt_424, 42406,
										[?ERRCODE(err424_times_reward_err), []]
									),
									NewState = State
							end
					end;
				_ ->
					?ERR("Player advance_treasure_map times err"),
					NewState = State
			end;
		_ ->
			%% 配置错误
			lib_server_send:send_to_uid(RoleId, pt_424, 42406,
				[?ERRCODE(err424_times_reward_err), []]
			),
			NewState = State
	end,
	{noreply, NewState};

do_handle_cast({update_times, RoleId, Times}, State) ->
	#treasure_map_state{role_times = RoleList} = State,
	case lists:keyfind(RoleId, #role_times.role_id, RoleList) of
		#role_times{receive_times = ReceiveList} = RoleTimes ->
			NewRoleList = lists:keystore(RoleId, #role_times.role_id, RoleList,
				RoleTimes#role_times{times = Times}),
			lib_treasure_map_advance:db_save_monthly_times(RoleId, Times, ReceiveList),
			%% 推送更新
			lib_server_send:send_to_uid(RoleId, pt_424, 42405, [Times, ReceiveList]),
			NewState = State#treasure_map_state{role_times = NewRoleList};
		_ ->
			NewRoleList = lists:keystore(RoleId, #role_times.role_id, RoleList,
				#role_times{role_id = RoleId, times = Times}),
			lib_treasure_map_advance:db_save_monthly_times(RoleId, Times, []),
			lib_server_send:send_to_uid(RoleId, pt_424, 42405, [Times, []]),
			NewState = State#treasure_map_state{role_times = NewRoleList}
	end,
	{noreply, NewState};

do_handle_cast({monthly_reward}, State) ->
	#treasure_map_state{role_times = RoleList} = State,
	TimeRewards = data_treasure_map:get_kv(advanced_map_times_reward),
	case TimeRewards of
		[{_, _, _}|_] ->
			TimesList = [TTimes||{TTimes, _, _}<-TimeRewards],
			F = fun(#role_times{role_id = RoleId, times = Times, receive_times = ReceiveList}, Num) ->
					FilterList = [T || T <- TimesList, Times >= T],
					CanReceive = FilterList -- ReceiveList,
					SendRewards = calc_rewards(CanReceive, TimeRewards),
					SendRewards1 = lib_goods_util:merge_same_goods(SendRewards),
					Title = utext:get(4240001), Content = utext:get(4240002),
					case (Num + 1) rem 30 == 0 of
						true -> timer:sleep(2000);
						_ -> ignore
					end,
					SendRewards1 =/= [] andalso
					lib_mail_api:send_sys_mail([RoleId], ?MOD_TREASURE_MAP, Title, Content, SendRewards1),
					%% 玩家进程的缓存数据需要清理
					lib_player:apply_cast(RoleId, ?APPLY_CAST_STATUS, ?NOT_HAND_OFFLINE,
						lib_treasure_map_advance, player_clean, []),
					Num + 1
				end,
			proc_lib:spawn_link(fun() ->
				lists:foldl(F, 0, RoleList),
				%% 清理数据库数据
				lib_treasure_map_advance:db_delete_monthly_times()
			end),
			% ?ERR("TreasureMap Advance SendMail Pid is [~w]~n", [Pid]),
			NewState = #treasure_map_state{};
		_ ->
			NewState = State
	end,
	{noreply, NewState};

do_handle_cast(_Msg, State) ->
	?ERR("Handle unknow msg[~w]~n", [_Msg]),
	{noreply, State}.

%% ---------------------------------------------------------------------------
do_handle_info({init_state}, State) ->
	case lib_treasure_map_advance:db_select_monthly_times() of
		InfoList = [_|_] ->
			RoleTimes = init_role_list(InfoList, []),
			NewState = State#treasure_map_state{role_times = RoleTimes};
		_ ->
			NewState = State
	end,
 	{noreply, NewState};

do_handle_info({'EXIT', Pid, Why}, State) ->
	case Why of
		normal -> ignore;
		shutdown -> ignore;
		_ -> ?ERR("Link pid[~w] exit:~p", [Pid, Why])
	end,
	{noreply, State};

do_handle_info(_Info, State) ->
	?ERR("Handle unknow msg[~w]~n", [_Info]),
	{noreply, State}.


%% ---------------------------- builtin func ----------------------------------
init_role_list([], RoleList) -> RoleList;
init_role_list([[RoleId, Times, ReceiveListStr]|T], RoleList) ->
	ReceiveTimes = util:bitstring_to_term(ReceiveListStr),
	RoleTimes = #role_times{role_id = RoleId, times = Times, receive_times = ReceiveTimes},
	init_role_list(T, [RoleTimes|RoleList]);
init_role_list([_|T], RoleList) ->
	init_role_list(T, RoleList).

calc_rewards(CanReceiveList, TimesRewards) ->
	F = fun(Times, TList) ->
		case lists:keyfind(Times, 1, TimesRewards) of
			{_, RewardId, Num} ->
				[{?TYPE_GOODS, RewardId, Num}|TList];
			_ ->
				TList
		end end,
	lists:foldl(F, [], CanReceiveList).