%%%-------------------------------------------------------------------
%%% @doc    社团 - 社团支援
%%% Module  : lib_guild_support_mod.erl
%%% Created : 2020-02-28
%%% @Author : tyl
%%%-------------------------------------------------------------------
-module(mod_guild_support).

-include("common.hrl").
-include("server.hrl").
-include("errcode.hrl").
-include("goods.hrl").
-include("guild.hrl").
-include("guild_support.hrl").
-include("def_module.hrl").
-include("def_goods.hrl").
-include("predefine.hrl").

-behaviour(gen_server).

%% API
-export([
	timer_clean/0
	,get_guild_list/0               %% 启动时更新最新公会列表
	,async_guild_list_from_guild/1

	,clean_collect_support/1        %% 社团采集结束清理数据

	,do_clean_thank/2
	,do_clean_log/2
]).

-export([start_link/0, apply_cast/3, 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]).

%% todo:1. 0点/1点定时清理数据
%%      2. 社团解散、合并清理(数据清理，guild_list清理)

-record(guild_support_state, {
	guild_list = []         %% 目前存在的公会列表(由公会进程消息更新)
}).

%% 每天1点10清理2天前的 感谢信 和 协助日志
timer_clean() ->
	gen_server:cast(?MODULE, {'timer_clean'}).

%% 获取公会进程的最新公会列表
async_guild_list_from_guild(GuildList) ->
	gen_server:cast(?MODULE, {'async_guild_list_from_guild', GuildList}).

%% 社团采集结束清理数据
clean_collect_support(GuildList) ->
	gen_server:cast(?MODULE, {'clean_collect_support', GuildList}).

apply_cast(Module, Method, Args) ->
	gen_server:cast(?MODULE, {'apply_cast', Module, Method, Args}).

%% ---------------------------------------------------------------------------
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),
	%% 延时10秒后去公会进程拿公会列表
	erlang:send_after(10*1000, self(), {'async_guild_list'}),
	State = #guild_support_state{},
	{ok, 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({'timer_clean'}, State) ->
	#guild_support_state{guild_list = GuildList} = State,
	%% 2天之前的都需要清理
	CleanTime = utime:that_day_before(2),
	%% 内存先清理，数据库分段清理
	clean_thank_two_days_ago(GuildList, CleanTime),
	clean_log_two_days_ago(GuildList, CleanTime),
	spawn(fun() ->
		db:execute(io_lib:format(?DELETE_SUPPORT_THANK, [CleanTime])),
		timer:sleep(2000),
		db:execute(io_lib:format(?DELETE_SUPPORT_LOG, [CleanTime]))
	end),
	{noreply, State};

do_handle_cast({'async_guild_list_from_guild', GuildList}, State) ->
	NewState = State#guild_support_state{guild_list = GuildList},
	{noreply, NewState};

do_handle_cast( {'clean_collect_support', GuildList}, State) ->
	F = fun(GuildId) ->
		guild_support_collect:clean_collect_support(GuildId)
	end,
	lists:map(F, GuildList),
	{noreply, State};

do_handle_cast({'apply_cast', Module, Method, Args}, State) ->
	apply(Module, Method, Args),
	{noreply, State};

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

%% ---------------------------------------------------------------------------
do_handle_info({'async_guild_list'}, State) ->
	mod_guild:apply_cast(?MODULE, get_guild_list, []),
	{noreply, State};

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

%% -------------------------- output func -----------------------------------
get_guild_list() ->
	GuildMap = lib_guild_data:get_guild_map(),
	GetGuildList =
	case maps:keys(GuildMap) of
		[GuildId|_] = GuildList when is_integer(GuildId), GuildId > 16#FFF -> GuildList;
		_ -> []
	end,
	mod_guild_support:async_guild_list_from_guild(GetGuildList),
	ok.

%% -------------------------- builtin func -----------------------------------
clean_thank_two_days_ago(GuildList, CleanTime) ->
	GFun = fun(GuildId) ->
		mod_guild:apply_cast_guild_member(GuildId, 1, ?MODULE, do_clean_thank, [CleanTime])
	end,
	lists:map(GFun, GuildList),
	ok.

do_clean_thank(#player_status{id = RoleId} = Player, CleanTime) ->
	%% 协助
	ThankList = guild_thank:get_support_thank_list(RoleId),
	SFun = fun(ThankPacket, TList) ->
		case ThankPacket of
			#guild_thank_packet{time = Time} when Time < CleanTime ->
				TList;
			#guild_thank_packet{} ->
				[ThankPacket|TList];
			_ ->
				TList
		end end,
	NewThankList = lists:foldl(SFun, [], ThankList),
	guild_thank:save_support_thank_list(RoleId, NewThankList),

	%% 拼单
	OrderThankList = guild_thank:get_order_thank_list(RoleId),
	OFun = fun(OrderThankPacket, TList1) ->
		case OrderThankPacket of
			#guild_order_thank_packet{time = Time1} when Time1 < CleanTime ->
				TList1;
			#guild_order_thank_packet{} ->
				[OrderThankPacket|TList1];
			_ ->
				TList1
		end end,
	NewOrderThankList = lists:foldl(OFun, [], OrderThankList),
	guild_thank:save_order_thank_list(RoleId, NewOrderThankList),

	{ok, Player}.

clean_log_two_days_ago(GuildList, CleanTime) ->
	GFun = fun(GuildId) ->
		mod_guild:apply_cast_guild_member(GuildId, 1, ?MODULE, do_clean_log, [CleanTime])
	       end,
	lists:map(GFun, GuildList),
	ok.

do_clean_log(#player_status{id = RoleId} = Player, CleanTime) ->
	%% 协助
	LogList = guild_thank:get_support_log_list(RoleId),
	SFun = fun(ThankLog, TList) ->
		case ThankLog of
			#guild_thank_log{time = Time} when Time < CleanTime ->
				TList;
			#guild_thank_log{} ->
				[ThankLog|TList];
			_ ->
				TList
		end end,
	NewLogList = lists:foldl(SFun, [], LogList),
	guild_thank:save_support_log_list(RoleId, NewLogList),

	%% 拼单
	OrderLogList = guild_thank:get_order_log_list(RoleId),
	OFun = fun(OrderThankLog, TList1) ->
		case OrderThankLog of
			#guild_order_thank_log{time = Time1} when Time1 < CleanTime ->
				TList1;
			#guild_order_thank_log{} ->
				[OrderThankLog|TList1];
			_ ->
				TList1
		end end,
	NewOrderLogList = lists:foldl(OFun, [], OrderLogList),
	guild_thank:save_order_log_list(RoleId, NewOrderLogList),

	{ok, Player}.