%%%-------------------------------------------------------------------
%%% @doc     公会竞速
%%% Module  : lib_guild_race_rank.erl
%%% Created : 2020-07-16
%%% @Author : tyl
%%%-------------------------------------------------------------------
-module(lib_guild_race_rank).

-include("common.hrl").
-include("server.hrl").
-include("figure.hrl").
-include("role.hrl").
-include("errcode.hrl").
-include("goods.hrl").
-include("guild.hrl").
-include("guild_race_rank.hrl").
-include("def_module.hrl").
-include("def_goods.hrl").
-include("rec_event.hrl").
-include("designation.hrl").
-include("def_event.hrl").
-include("predefine.hrl").
-include("common_rank.hrl").
-include("custom_act.hrl").

-compile(export_all).


%% 战力变更
handle_event(Player, #event_callback{type_id = ?EVENT_COMBAT_POWER}) when is_record(Player, player_status) ->
	#player_status{id = RoleId, figure = Figure, guild = Guild, dsgt_status = DsgtStatus} = Player,
	#dsgt_status{dsgt_map = DsgtMap} = DsgtStatus,
	%% 战力需要去除社团竞榜的称号战力
	AddAttr =
	case maps:to_list(DsgtMap) of
		DsgtList = [_|_] ->
			lists:foldl(fun({_K, #designation{id = DsgId}}, Acc) ->
				case data_designation:get_by_id(DsgId) of
					#base_designation{force_cancel = 1, attr_list = AttrList} ->
						AttrList ++ Acc;
					_ ->
						Acc
				end
			end, [], DsgtList);
		_ ->
			[]
	end,
	case AddAttr =/= [] of
		true ->
			PartialAttr = attr_conv:to_attr_record(AddAttr),
			AddPower = lib_player_attr:calc_attr_power(PartialAttr);
		_ ->
			AddPower = 0
	end,
	case is_open_act() of
		true ->
			Guild#status_guild.id > 0 andalso
				mod_guild_race_rank:power_change(Guild#status_guild.id, RoleId, max(0, Figure#figure.power-AddPower));
		_ ->
			ignore
	end,
	{ok, Player};

%% 超级贵族
handle_event(Player = #player_status{}, #event_callback{type_id = ?EVENT_SUP_VIP_CHANGE}) ->
	#player_status{id = RoleId, figure = Figure, guild = Guild} = Player,
	#figure{name = Name, vip = Vip, sup_vip = SupVip} = Figure,
	Guild#status_guild.id > 0 andalso mod_guild_race_rank:figure_change(Guild#status_guild.id, RoleId, [Name, Vip, SupVip], ?FIGURE_CHANGE_SUP_VIP),
	{ok, Player};

%% vip等级
handle_event(Player = #player_status{}, #event_callback{type_id = ?EVENT_VIP}) ->
	#player_status{id = RoleId, figure = Figure, guild = Guild} = Player,
	#figure{name = Name, vip = Vip, sup_vip = SupVip} = Figure,
	Guild#status_guild.id > 0 andalso mod_guild_race_rank:figure_change(Guild#status_guild.id, RoleId, [Name, Vip, SupVip], ?FIGURE_CHANGE_VIP),
	{ok, Player};

%% 名字
handle_event(Player = #player_status{}, #event_callback{type_id = ?EVENT_RENAME}) ->
	#player_status{id = RoleId, figure = Figure, guild = Guild} = Player,
	#figure{name = Name, vip = Vip, sup_vip = SupVip} = Figure,
	Guild#status_guild.id > 0 andalso mod_guild_race_rank:figure_change(Guild#status_guild.id, RoleId, [Name, Vip, SupVip], ?FIGURE_CHANGE_NAME),
	{ok, Player};

handle_event(Player, _Event) ->
	{ok, Player}.

%% 社团进程同步玩家数据
%% {RoleId, RoleName, VipLv, SupVip, GuildId, Position, Power} = RoleInfo,
%% {GuildId, GuildName, GuildLv} = GuildInfo,
sync_guild_msg() ->
	GuildMap = lib_guild_data:get_guild_map(),
	GuildList = lib_guild_mod:get_guild_list(GuildMap, 0),
	SynGuildMsg = [{GuildId, GuildName, GuildLv}||#guild{id = GuildId, name = GuildName, lv = GuildLv}<-GuildList],
	F = fun({GuildId, _, _}, TList) ->
		GuildMemberMap = lib_guild_data:get_guild_member_map(GuildId),
		GuildMemberL = [{RoleId, Figure#figure.name, Figure#figure.vip, Figure#figure.sup_vip, GuildId, Position, Power, Live}||
			#guild_member{id = RoleId, figure = Figure, position = Position, combat_power = Power, labors = Live}<-maps:values(GuildMemberMap)],
		GuildMemberL ++ TList
	end,
	SynMemberMsg = lists:foldl(F, [], SynGuildMsg),
	mod_guild_race_rank:sync_guild_msg(SynMemberMsg, SynGuildMsg),
	ok.

%% 同步排行到社团进程 & 排行榜进程
sync_race_rank(State) ->
	#guild_race_rank_state{guild_rank_list = GuildRankList} = State,
	SyncInfo = [{GuildId, Rank}||#guild_rank{guild_id = GuildId, rank = Rank}<-GuildRankList],
	SyncInfo =/= [] andalso
		begin
			mod_guild:apply_cast(?MODULE, update_add_mem_num, [SyncInfo]),
			mod_common_rank:apply_cast(?MODULE, update_common_rank, [?RANK_TYPE_GUILD, SyncInfo])
		end,
	ok.

%% 社团进程更新扩展人数
update_add_mem_num(SyncInfo) ->
	AllGuildMap = lib_guild_data:get_guild_map(),
	F = fun({GuildId, RaceRank}, TAllGuildMap) ->
		case maps:get(GuildId, TAllGuildMap, []) of
			#guild{} = Guild ->
				AddMemNum = calc_add_mem_num(RaceRank),
				NewGuild = Guild#guild{race_rank = RaceRank, add_member_num = AddMemNum},
				maps:put(GuildId, NewGuild, TAllGuildMap);
			_ ->
				TAllGuildMap
		end end,
	NewAllGuildMap = lists:foldl(F, AllGuildMap, SyncInfo),
	lib_guild_data:save_guild_map(NewAllGuildMap),
	ok.

%% 排行榜进程更新扩展人数
update_common_rank(State, [RankType, SyncInfo]) ->
	#common_rank_state{guild_maps = RankMaps} = State,
	RankList = maps:get(RankType, RankMaps, []),
	F = fun({GuildId, RaceRank}, TRankList) ->
		case lists:keyfind(GuildId, #common_rank_guild.guild_id, TRankList) of
			#common_rank_guild{} = CommonRankGuild ->
				AddMemNum = calc_add_mem_num(RaceRank),
				lists:keystore(GuildId, #common_rank_guild.guild_id, TRankList, CommonRankGuild#common_rank_guild{add_mem_num = AddMemNum});
			_ ->
				TRankList
		end end,
	NewRankList = lists:foldl(F, RankList, SyncInfo),
	NewRankMaps = maps:put(RankType, NewRankList, RankMaps),
	{ok, State#common_rank_state{guild_maps = NewRankMaps}}.

%% 根据排名计算社团扩展人数
calc_add_mem_num(RaceRank) ->
	case lists:member(RaceRank, ?GUILD_TOP_RANK) of
		true ->
			OpenDay = util:get_open_day(),
			case data_guild_race_rank:get_guild_race_rank_expand_cfg(OpenDay) of
				ExpandNum when is_integer(ExpandNum) -> ExpandNum;
				_ ->
					data_guild_race_rank:get_guild_race_rank_expand_cfg(?DEFAULT_END_DAY)
			end;
		_ -> 0
	end.

%% 活动是否在规定时间内(1-7天)
is_open_act() ->
	OpenDay = util:get_open_day(),
	case lib_custom_act_util:get_act_cfg_info(?CUSTOM_ACT_TYPE_GUILD_RACE_RANK, 1) of
		#custom_act_cfg{opday_lim = [{StartDay, EndDay}]} ->
			case OpenDay =< max(7, EndDay - 1) andalso OpenDay >= StartDay of
				true -> true;
				_ -> false
			end;
		_ ->
			false
	end.

%% 活动结束日期
get_end_day() ->
	case lib_custom_act_util:get_act_cfg_info(?CUSTOM_ACT_TYPE_GUILD_RACE_RANK, 1) of
		#custom_act_cfg{opday_lim = [{_, EndDay}]} ->
			max(7, EndDay - 1);
		_ ->
			7
	end.

%% 判断是否开服第一天第一次结算
is_first_reward() ->
	OpenDay = util:get_open_day(),
	{_NowDate, {NowH,NowM,_}} = calendar:local_time(),
	Now = NowH * 60 + NowM,
	{StartH, StartM} = data_guild_race_rank:get_guild_race_rank_kv_cfg(reward_time),
	StartMin = StartH * 60 + StartM,
	case lib_custom_act_util:get_act_cfg_info(?CUSTOM_ACT_TYPE_GUILD_RACE_RANK, 1) of
		#custom_act_cfg{opday_lim = [{StartDay, _}]} -> ok;
		_ -> StartDay = 1
	end,
	case OpenDay == StartDay of
		%% 第一天11点前突然停服,停服不结算,重启后需要重新排序
		true ->
			case Now >= StartMin of
				false -> false;
				_ -> true
			end;
		_ -> true
	end.

%% 定制活动控制触发,条件满足开始结算
%% 之后每小时结算由进程内部管理
check_start_send_reward(State) ->  %% TODO:活动状态检测
	#guild_race_rank_state{ref = Ref} = State,
	case Ref of
		[] ->
			case is_open_act() of
				true ->
					timer_check(State, 1);
				_ ->
					util:cancel_timer(Ref), NewRef = [],
					State#guild_race_rank_state{ref = NewRef}
			end;
		_ ->
			State
	end.

%% 定制活动控制,活动结束
%% 清理数据
act_end(State) ->
	%% 先重新排行
	State0 = deal_with_guild_disband_or_mem_leave(State),
	State1 = timer_recalc_rank(State0),
	timer_send_reward(State1, ?FIRST_SEND_REWARD_NO),
	%% 同步新排行到社团进程
	sync_race_rank(State1),
	#guild_race_rank_state{guild_rank_list = GuildRankList, member_rank_map = MemberRankMap, ref = Ref} = State1,
	NewGuildL = [GuildId||#guild_rank{rank = Rank, guild_id = GuildId}<-GuildRankList,lists:member(Rank, ?GUILD_TOP_RANK)],
	F = fun(GuildId) ->
		case maps:get(GuildId, MemberRankMap, []) of
			[_|_] = MemberRankList ->
				F1 = fun(#member_rank{role_id = RoleId, rank = MemberRank}) ->
					case lists:keyfind(GuildId, #guild_rank.guild_id, GuildRankList) of
						#guild_rank{rank = Rank} -> ok;
						_ -> Rank = 1
					end,
					case data_guild_race_rank:get_guild_race_rank_reward_cfg(Rank, MemberRank) of
						#guild_race_rank_reward_cfg{reward = [{_, DsgId, _}]} ->
							DsgName = get_dsg_name(DsgId);
						_ ->
							DsgName = ""
					end,
					Title = utext:get(3316609), Content = utext:get(3316610, [Rank, DsgName]),
					lib_mail_api:send_sys_mail([RoleId], ?MOD_AC_CUSTOM, ?CUSTOM_ACT_TYPE_GUILD_RACE_RANK, Title, Content, [])
				end,
				lists:map(F1, MemberRankList);
			_ ->
				skip
		end end,
	lists:map(F, NewGuildL),
	send_expand_forever_mail(NewGuildL),
	util:cancel_timer(Ref),
	%% 最新排名写到数据库
	NewState = move_rank(State1),
	RoleMap = make_role_guild_map(NewState),
	NewState#guild_race_rank_state{ref = [], role_guild_map = RoleMap}.

%% 整理成角色公会映射
make_role_guild_map(State) ->
	#guild_race_rank_state{member_rank_map = MemberRankMap} = State,
	MemTupleList = maps:to_list(MemberRankMap),
	MFun = fun({GuildId, MemberList}, TRoleMap) ->
		RoleList = [RoleId||#member_rank{role_id = RoleId}<-MemberList],
		%% 存数据库
		spawn(fun() -> db_save_guild_race_role(GuildId, RoleList) end),
		F = fun(RoleId, TMap) ->
			maps:put(RoleId, GuildId, TMap)
		    end,
		lists:foldl(F, TRoleMap, RoleList)
	end,
	RoleMap = lists:foldl(MFun, #{}, MemTupleList),
	RoleMap.

%% 获取所在真实社团Id
%% 第七天后玩家可能会变更社团 或 退出社团，但仍需展示前七天的数据，
%% 即需要获取前七天结算时的社团Id
get_real_guild_id(RoleId, GuildId, RoleGuildMap) ->
	OpenDay = util:get_open_day(),
	EndDay = get_end_day(),
	case OpenDay > EndDay of
		true -> maps:get(RoleId, RoleGuildMap, 0);
		_ -> GuildId
	end.

%% 每小时触发结算
timer_check(State, IsFirst) ->
	#guild_race_rank_state{ref = Ref} = State,
	case is_open_act() of
		true ->
			%% 重新排序(此处old_rank还未赋值,send_reward必须严格使用这里的数据)
			State0 = deal_with_guild_disband_or_mem_leave(State),
			State1 = timer_recalc_rank(State0),
			timer_send_reward(State1, IsFirst),
			%% 同步新排行到社团进程
			sync_race_rank(State1),
			%% 刷新排行榜,将新的数据移植到old部分
			NewState = move_rank(State1),
			case data_guild_race_rank:get_guild_race_rank_kv_cfg(refresh_interval) of
				Interval when is_integer(Interval) -> skip;
				_ -> Interval = ?ONE_HOUR_SECOND
			end,
			% Interval = 30,  %% test
			NewRef = util:send_after(Ref, Interval * 1000, self(), {timer_check}),
			NewState#guild_race_rank_state{ref = NewRef};
		_ ->
			util:cancel_timer(Ref), NewRef = [],
			State#guild_race_rank_state{ref = NewRef}
	end.

%% 处理解散的社团
deal_with_guild_disband_or_mem_leave(State) ->
	#guild_race_rank_state{
		guild_rank_list = GuildRankList, member_rank_map = MemberRankMap
		,disband_rank_list = DisbandGuildList, leave_member_map = LeaveMemMap
	} = State,
	LeaveTypeList  = maps:to_list(LeaveMemMap),
	MemberRankMap1 = do_deal_with_mem_leave(LeaveTypeList, MemberRankMap),
	{NewGuildRankList, NewMemberRankMap} =
	do_deal_with_guild_disband(DisbandGuildList, State, GuildRankList, MemberRankMap1),
	%% 删除任务数据
	State1 = lib_guild_race_rank_task:delete_race_rank_task(State, DisbandGuildList),
	State1#guild_race_rank_state{disband_rank_list = [], leave_member_map = #{},
		guild_rank_list = NewGuildRankList, member_rank_map = NewMemberRankMap
	}.

do_deal_with_mem_leave([], MemberRankMap) ->
	MemberRankMap;
do_deal_with_mem_leave([{GuildId, MemList}|T], MemberRankMap) ->
	%% 数据库操作
	MemberRankList = maps:get(GuildId, MemberRankMap, []),
	F = fun(RoleId, TMemberRankList) ->
		db_delete_guild_race_rank_member(RoleId),
		lists:keydelete(RoleId, #member_rank.role_id, TMemberRankList)
	end,
	NewMemberRankList = lists:foldl(F, MemberRankList, MemList),
	NewMemberRankMap = maps:put(GuildId, NewMemberRankList, MemberRankMap),
	do_deal_with_mem_leave(T, NewMemberRankMap).

do_deal_with_guild_disband([], _State, GuildRankList, MemberRankMap) ->
	{GuildRankList, MemberRankMap};
do_deal_with_guild_disband([GuildId|T], State, GuildRankList, MemberRankMap) ->
	NewGuildRankList = lists:keydelete(GuildId, #guild_rank.guild_id, GuildRankList),
	NewMemberRankMap = maps:remove(GuildId, MemberRankMap),
	%% 数据库 %% todo:如果没有数据可以删除？
	DbF = fun() ->
		lib_guild_race_rank:db_delete_guild_race_rank_guild(GuildId),
		lib_guild_race_rank:db_delete_guild_race_rank(GuildId),
		lib_guild_race_rank_task:db_delete_race_rank_task(GuildId),
		ok
	end,
	case catch db:transaction(DbF) of
		ok ->
			%% 取消称号
			F = fun(TMemberRank) ->
				#member_rank{role_id = RoleId} = TMemberRank,
				mod_guild_race_rank:cancel_dsg_after_leave_guild(State, RoleId, GuildId)
			    end,
			lists:map(F, maps:get(GuildId, MemberRankMap, [])),
			do_deal_with_guild_disband(T, State, NewGuildRankList, NewMemberRankMap);
		_ ->
			?ERR("Disband guild error:~p~n", [{?MODULE, GuildId}]),
			do_deal_with_guild_disband(T, State, GuildRankList, MemberRankMap)
	end.

%% 对两个榜单进行重新排序
timer_recalc_rank(State) ->
	#guild_race_rank_state{guild_rank_list = GuildRankList, member_rank_map = MemberRankMap} = State,
	F = fun(GuildId, MemberRankList, {AccList, AccMap}) ->
		NewMemberRankList = mod_guild_race_rank:sort_member_rank(MemberRankList),
		LimitMemberRank = lists:filter(fun(TMemberRank) -> TMemberRank#member_rank.rank =< 10 end, NewMemberRankList),
		NewAccMap = maps:put(GuildId, NewMemberRankList, AccMap),
		%% 战力排行刷新
		AccList1 =
			case lists:keyfind(GuildId, #guild_rank.guild_id, AccList) of
				#guild_rank{sum_power = OldSumPower} = GuildRank ->
					SumPower = lists:sum([TPower||#member_rank{power = TPower}<- LimitMemberRank]),
					case OldSumPower =/= SumPower of
						true ->
							lib_guild_race_rank:db_update_guild_race_rank_power(GuildId, SumPower),
							TAccList1 = lists:keystore(GuildId, #guild_rank.guild_id, AccList, GuildRank#guild_rank{sum_power = SumPower}),
							TAccList1;
						_ ->
							AccList
					end;
				_ ->
					AccList
			end,
		%% 活跃值只做统计，不区分个人排行(社团排行也不存库)
		NewAccList =
			case lists:keyfind(GuildId, #guild_rank.guild_id, AccList1) of
				#guild_rank{sum_live = OldSumLive} = GuildRank1 ->
					SumLive = lists:sum([TLive||#member_rank{live = TLive}<- NewMemberRankList]),
					case OldSumLive < SumLive of
						true ->
							lib_guild_race_rank:db_update_guild_race_rank_old_live(GuildId, SumLive),
							TAccList2 = lists:keystore(GuildId, #guild_rank.guild_id, AccList1, GuildRank1#guild_rank{sum_live = SumLive}),
							TAccList2;
						_ ->
							AccList1
					end;
				_ ->
					AccList1
			end,
		{NewAccList, NewAccMap}
	    end,
	{NewGuildRankList, NewMemberRankMap} = maps:fold(F, {GuildRankList, MemberRankMap}, MemberRankMap),
	%% 社团榜统一重新排序
	SortGuildRankList  = mod_guild_race_rank:sort_guild_rank(NewGuildRankList),
	SortGuildRankList1 = mod_guild_race_rank:sort_guild_live_rank(SortGuildRankList),
	NewGuildRankList1  = mod_guild_race_rank:update_guild_limit_num(SortGuildRankList1),
	%% 日志 todo:加上活跃榜日志
	add_guild_log(NewGuildRankList1),
	add_role_log(NewMemberRankMap, NewGuildRankList1),
	NewState = State#guild_race_rank_state{guild_rank_list = NewGuildRankList1, member_rank_map = NewMemberRankMap},
	NewState.

add_guild_log(GuildRankList) ->
	OpenDay = util:get_open_day(),
	F = fun(#guild_rank{guild_id = GuildId, guild_name = GuildName, sum_power = SumPower, rank = Rank}) ->
		lib_log_api:log_guild_race_rank_guild(GuildId, GuildName, SumPower, Rank, OpenDay)
		end,
	spawn(fun() -> lists:map(F, GuildRankList) end),
	ok.

add_role_log(MemberRankMap, GuildRankList) ->
	OpenDay = util:get_open_day(),
	F = fun(GuildId, MemberList) ->
		ForFun = fun(#member_rank{role_id = RoleId, rank = Rank, power = Power}) ->
			case lists:keyfind(GuildId, #guild_rank.guild_id, GuildRankList) of
				#guild_rank{rank = GuildRank} ->
					lib_log_api:log_guild_race_rank_role(RoleId, GuildId, GuildRank, Power, Rank, OpenDay);
				_ -> ignore
			end end,
		lists:map(ForFun, MemberList)
	end,
	spawn(fun() -> maps:map(F, MemberRankMap) end),
	ok.

%% 每一小时发放奖励(只负责奖励发放和取消,无返回)
timer_send_reward(State, IsFirst) ->
	#guild_race_rank_state{guild_rank_list = GuildRankList} = State,
	case IsFirst of
		?FIRST_SEND_REWARD_YES ->
			NewGuildL = [GuildId||#guild_rank{rank = Rank, guild_id = GuildId}<-GuildRankList,lists:member(Rank, ?GUILD_TOP_RANK)],
			send_expand_success_mail(NewGuildL, [], true),
			send_reward([], NewGuildL, State, IsFirst);
		_ ->
			NewGuildL = [GuildId||#guild_rank{rank = Rank, guild_id = GuildId}<-GuildRankList,lists:member(Rank, ?GUILD_TOP_RANK)],
			OldGuildL = [GuildId1||#guild_rank{old_rank = OldRank, guild_id = GuildId1}<-GuildRankList,lists:member(OldRank, ?GUILD_TOP_RANK)],  % true
			% OldGuildL = [], % test
			UpGuildL = NewGuildL -- OldGuildL,
			DownGuildL = OldGuildL -- NewGuildL,
			%% 社团新上榜的发放奖励
			send_reward(NewGuildL, UpGuildL, State, IsFirst),
			send_expand_success_mail(NewGuildL, UpGuildL, false),
			%% 社团掉榜的取消奖励
			cancel_reward(DownGuildL, State),
			send_expand_fail_mail(DownGuildL),
			%% 个人掉榜的取消奖励,个人上榜的发奖励
			KeepGuildL = NewGuildL -- UpGuildL,
			change_reward(KeepGuildL, State, IsFirst)
	end,
	ok.

send_reward(_NewGuildL, UpGuildL, State, IsFirst) ->
	#guild_race_rank_state{guild_rank_list = GuildRankList, member_rank_map = MemberRankMap} = State,
	case IsFirst of
		%% 第一次发奖,直接根据排行来发
		?FIRST_SEND_REWARD_YES ->
			F = fun(GuildId) ->
				#guild_rank{rank = Rank} = lists:keyfind(GuildId, #guild_rank.guild_id, GuildRankList),
				case maps:get(GuildId, MemberRankMap, []) of
					[_|_] = MemberRankList ->
						F1 = fun(#member_rank{rank = MemberRank, role_id = RoleId}) when MemberRank =< ?SEND_REWARD_RANK_NEED ->
							case data_guild_race_rank:get_guild_race_rank_reward_cfg(Rank, MemberRank) of
								#guild_race_rank_reward_cfg{reward = [{_, DsgId, _}]} ->
									%% 发邮件
									DsgName = get_dsg_name(DsgId),
									Title = utext:get(3316601), Content = utext:get(3316602,[MemberRank, DsgName]),
									lib_mail_api:send_sys_mail([RoleId], ?MOD_AC_CUSTOM, ?CUSTOM_ACT_TYPE_GUILD_RACE_RANK, Title, Content, []),
									{ok, BinData} = pt_407:write(40702, [MemberRank, DsgId]),
									lib_server_send:send_to_uid(RoleId, BinData),
									lib_designation_api:active_dsgt_common(RoleId, DsgId);
								_ -> skip
							end;
							(_) -> skip
						     end,
						lists:map(F1, MemberRankList);
					_ ->
						skip
				end end,
			lists:map(F, UpGuildL);
		_ ->
			%% 后面的发奖需要筛选出还在top_rank上的排行保持不变(即使前三变动),只给改变的社团排位发奖(逻辑有问题)
			% KeepGuild = NewGuildL -- UpGuildL,
			% Filter = fun(TGuildId, TList) ->
			%	case lists:keyfind(TGuildId, #guild_rank.guild_id, GuildRankList) of
			%		#guild_rank{old_rank = TOldRank} ->
			%			[TOldRank|TList];
			%		_ -> TList
			%	end end,
			%KeepRank = lists:foldl(Filter, [], KeepGuild),
			%ChangeRank = [1,2,3] -- KeepRank,
			%?INFO_TTY("ChangeRank is ~w~n",[ChangeRank]),
			F = fun(GuildId) ->
				%% 给一个排位
				#guild_rank{rank = Rank, old_rank = OldRank} = lists:keyfind(GuildId, #guild_rank.guild_id, GuildRankList),
				case OldRank == Rank of
					%% 社团排名不变(由change_reward负责)
					true ->
						skip;
					%% 社团排名发生变更
					_ ->
						case maps:get(GuildId, MemberRankMap, []) of
							[_|_] = MemberRankList ->
								do_send_reward(Rank, OldRank, MemberRankList);
							_ ->
								skip
						end
				end end,
			lists:map(F, UpGuildL)
	end.

do_send_reward(GuildRank, GuildOldRank, MemberRankList) ->
	F = fun(#member_rank{rank = MemberRank, old_rank = OldMemRank, role_id = RoleId}) ->
		case data_guild_race_rank:get_guild_race_rank_reward_cfg(GuildRank, MemberRank) of
			#guild_race_rank_reward_cfg{reward = [{_, DsgId, _}]} ->
				case data_guild_race_rank:get_guild_race_rank_reward_cfg(GuildOldRank, OldMemRank) of
					#guild_race_rank_reward_cfg{reward = [{_, OldDsgId, _}]} -> ok;
					_ -> OldDsgId = 0
				end,
				case OldDsgId =< 0 of
					true ->
						%% 新进前10
						DsgName = get_dsg_name(DsgId),
						Title = utext:get(3316601), Content = utext:get(3316602,[MemberRank, DsgName]),
						lib_mail_api:send_sys_mail([RoleId], ?MOD_AC_CUSTOM, ?CUSTOM_ACT_TYPE_GUILD_RACE_RANK, Title, Content, []),
						{ok, BinData} = pt_407:write(40702, [MemberRank, DsgId]),
						lib_server_send:send_to_uid(RoleId, BinData),
						lib_designation_api:active_dsgt_common(RoleId, DsgId);
					_ ->
						%% 前10变动(已经排除OldMemRank=0情况)
						case OldMemRank == MemberRank of
							true ->
								case OldDsgId == DsgId of
									true -> ignore;
									_ ->
										DsgName = get_dsg_name(DsgId),
										Title = utext:get(3316601), Content = utext:get(3316602,[MemberRank, DsgName]),
										lib_mail_api:send_sys_mail([RoleId], ?MOD_AC_CUSTOM, ?CUSTOM_ACT_TYPE_GUILD_RACE_RANK, Title, Content, []),
										lib_designation_api:cancel_dsgt(RoleId, OldDsgId),
										{ok, BinData} = pt_407:write(40702, [MemberRank, DsgId]),
										lib_server_send:send_to_uid(RoleId, BinData),
										lib_designation_api:active_dsgt_common(RoleId, DsgId)
								end;
							_ ->
								case OldMemRank =< MemberRank of
									%% 排名下降
									true ->
										OldDsgName = get_dsg_name(OldDsgId),
										DsgName = get_dsg_name(DsgId),
										Title = utext:get(3316603), Content = utext:get(3316604, [OldMemRank, MemberRank, OldDsgName, DsgName]),
										lib_mail_api:send_sys_mail([RoleId], ?MOD_AC_CUSTOM, ?CUSTOM_ACT_TYPE_GUILD_RACE_RANK, Title, Content, []),
										lib_designation_api:cancel_dsgt(RoleId, OldDsgId),
										{ok, BinData} = pt_407:write(40702, [MemberRank, DsgId]),
										lib_server_send:send_to_uid(RoleId, BinData),
										lib_designation_api:active_dsgt_common(RoleId, DsgId);
									%% 排名上升
									_ ->
										DsgName = get_dsg_name(DsgId),
										Title = utext:get(3316605), Content = utext:get(3316606, [OldMemRank, MemberRank, DsgName]),
										lib_mail_api:send_sys_mail([RoleId], ?MOD_AC_CUSTOM, ?CUSTOM_ACT_TYPE_GUILD_RACE_RANK, Title, Content, []),
										lib_designation_api:cancel_dsgt(RoleId, OldDsgId),
										{ok, BinData} = pt_407:write(40702, [MemberRank, DsgId]),
										lib_server_send:send_to_uid(RoleId, BinData),
										lib_designation_api:active_dsgt_common(RoleId, DsgId)
								end
						end
				end;
			%% 掉出前10
			_ ->
				case data_guild_race_rank:get_guild_race_rank_reward_cfg(GuildOldRank, OldMemRank) of
					#guild_race_rank_reward_cfg{reward = [{_, OldDsgId, _}]} -> ok;
					_ -> OldDsgId = 0
				end,
				case OldDsgId > 0 of
					true ->
						OldDsgName = get_dsg_name(OldDsgId),
						Title = utext:get(3316607), Content = utext:get(3316608, [OldMemRank, MemberRank, OldDsgName]),
						lib_mail_api:send_sys_mail([RoleId], ?MOD_AC_CUSTOM, ?CUSTOM_ACT_TYPE_GUILD_RACE_RANK, Title, Content, []),
						lib_designation_api:cancel_dsgt(RoleId, OldDsgId);
					_ -> skip
				end
		end
	end,
	lists:map(F, MemberRankList).

change_reward(KeepGuildL, State, IsFirst) ->
	#guild_race_rank_state{guild_rank_list = GuildRankList, member_rank_map = MemberRankMap} = State,
	case IsFirst of
		?FIRST_SEND_REWARD_YES -> skip;
		_ ->
			F = fun(GuildId) ->
				#guild_rank{old_rank = OldRank} = lists:keyfind(GuildId, #guild_rank.guild_id, GuildRankList),
				case maps:get(GuildId, MemberRankMap, []) of
					[_|_] = MemberRankList ->
							%% 新进社团
						F1 = fun(#member_rank{rank = MemberRank, role_id = RoleId, old_rank = OldMemberRank})
							when OldMemberRank == 0 ->
								case MemberRank =< ?SEND_REWARD_RANK_NEED of
									true ->
										DsgId = get_dsg_id(OldRank, MemberRank),
										DsgName = get_dsg_name(DsgId),
										Title = utext:get(3316601), Content = utext:get(3316602,[MemberRank, DsgName]),
										lib_mail_api:send_sys_mail([RoleId], ?MOD_AC_CUSTOM, ?CUSTOM_ACT_TYPE_GUILD_RACE_RANK, Title, Content, []),
										{ok, BinData} = pt_407:write(40702, [MemberRank, DsgId]),
										lib_server_send:send_to_uid(RoleId, BinData),
										lib_designation_api:active_dsgt_common(RoleId, DsgId);
									_ ->
										skip
								end;
							%% 社团内新进前10,发奖励
							(#member_rank{rank = MemberRank, role_id = RoleId, old_rank = OldMemberRank})
							when MemberRank =< ?SEND_REWARD_RANK_NEED, OldMemberRank > ?SEND_REWARD_RANK_NEED ->
								DsgId = get_dsg_id(OldRank, MemberRank),
								DsgName = get_dsg_name(DsgId),
								Title = utext:get(3316601), Content = utext:get(3316602,[MemberRank, DsgName]),
								lib_mail_api:send_sys_mail([RoleId], ?MOD_AC_CUSTOM, ?CUSTOM_ACT_TYPE_GUILD_RACE_RANK, Title, Content, []),
								{ok, BinData} = pt_407:write(40702, [MemberRank, DsgId]),
								lib_server_send:send_to_uid(RoleId, BinData),
								lib_designation_api:active_dsgt_common(RoleId, DsgId);
							%% 社团内掉出10名的发送取消协议
							(#member_rank{rank = MemberRank, role_id = RoleId, old_rank = OldMemberRank})
								when MemberRank > ?SEND_REWARD_RANK_NEED, OldMemberRank =< ?SEND_REWARD_RANK_NEED  ->
								DsgId = get_dsg_id(OldRank, MemberRank),
								DsgName = get_dsg_name(DsgId),
								Title = utext:get(3316607), Content = utext:get(3316608, [OldMemberRank, MemberRank, DsgName]),
								lib_mail_api:send_sys_mail([RoleId], ?MOD_AC_CUSTOM, ?CUSTOM_ACT_TYPE_GUILD_RACE_RANK, Title, Content, []),
								lib_designation_api:cancel_dsgt(RoleId, DsgId);
							%% 社团内排名上升
							(#member_rank{rank = MemberRank, role_id = RoleId, old_rank = OldMemberRank})
								when MemberRank =< ?SEND_REWARD_RANK_NEED, MemberRank < OldMemberRank  ->
								OldDsgId = get_dsg_id(OldRank, OldMemberRank),
								NewDsgId = get_dsg_id(OldRank, MemberRank),
								DsgName = get_dsg_name(NewDsgId),
								%% 如果处于同一排名段,则忽略
								case NewDsgId == OldDsgId of
									true ->
										ignore;
									_ ->
										Title = utext:get(3316605), Content = utext:get(3316606, [OldMemberRank, MemberRank, DsgName]),
										lib_mail_api:send_sys_mail([RoleId], ?MOD_AC_CUSTOM, ?CUSTOM_ACT_TYPE_GUILD_RACE_RANK, Title, Content, []),
										lib_designation_api:cancel_dsgt(RoleId, OldDsgId),
										{ok, BinData} = pt_407:write(40702, [MemberRank, NewDsgId]),
										lib_server_send:send_to_uid(RoleId, BinData),
										lib_designation_api:active_dsgt_common(RoleId, NewDsgId)
								end;
							%% 社团内排名下降(注意排名平跳不操作)
							(#member_rank{rank = MemberRank, role_id = RoleId, old_rank = OldMemberRank})
								when MemberRank =< ?SEND_REWARD_RANK_NEED, MemberRank > OldMemberRank  ->
								OldDsgId = get_dsg_id(OldRank, OldMemberRank),
								NewDsgId = get_dsg_id(OldRank, MemberRank),
								OldDsgName = get_dsg_name(OldDsgId),
								DsgName = get_dsg_name(NewDsgId),
								%% 如果处于同一排名段,则忽略
								case NewDsgId == OldDsgId of
									true ->
										ignore;
									_ ->
										Title = utext:get(3316603), Content = utext:get(3316604, [OldMemberRank, MemberRank, OldDsgName, DsgName]),
										lib_mail_api:send_sys_mail([RoleId], ?MOD_AC_CUSTOM, ?CUSTOM_ACT_TYPE_GUILD_RACE_RANK, Title, Content, []),
										lib_designation_api:cancel_dsgt(RoleId, OldDsgId),
										{ok, BinData} = pt_407:write(40702, [MemberRank, NewDsgId]),
										lib_server_send:send_to_uid(RoleId, BinData),
										lib_designation_api:active_dsgt_common(RoleId, NewDsgId)
								end;
							(_) -> skip
						end,
						lists:map(F1, MemberRankList);
					_ ->
						skip
				end
			end,
			lists:map(F, KeepGuildL)
	end.

cancel_reward(DownGuildL, State) ->
	#guild_race_rank_state{guild_rank_list = GuildRankList, member_rank_map = MemberRankMap} = State,
	F = fun(GuildId) ->
		#guild_rank{old_rank = OldRank} = lists:keyfind(GuildId, #guild_rank.guild_id, GuildRankList),
		case maps:get(GuildId, MemberRankMap, []) of
			[_|_] = MemberRankList ->
				F1 = fun(#member_rank{old_rank = OldMemberRank, role_id = RoleId}) ->
					case data_guild_race_rank:get_guild_race_rank_reward_cfg(OldRank, OldMemberRank) of
						#guild_race_rank_reward_cfg{reward = [{_, DsgId, _}]} ->
							%% 发邮件
							DsgName = get_dsg_name(DsgId),
							Title = utext:get(3316613), Content = utext:get(3316614, [DsgName]),
							lib_mail_api:send_sys_mail([RoleId], ?MOD_AC_CUSTOM, ?CUSTOM_ACT_TYPE_GUILD_RACE_RANK, Title, Content, []),
							lib_designation_api:cancel_dsgt(RoleId, DsgId);
						_ -> skip
					end;
					(_) -> skip
				     end,
				lists:map(F1, MemberRankList);
			_ ->
				skip
		end end,
	lists:map(F, DownGuildL).

get_dsg_id(GuildRank, MemberRank) ->
	case data_guild_race_rank:get_guild_race_rank_reward_cfg(GuildRank, MemberRank) of
		#guild_race_rank_reward_cfg{reward = [{_, DsgId, _}]} -> skip;
		_ ->
			DsgId = 0
	end,
	DsgId.

get_dsg_name(DsgId) ->
	case data_designation:get_by_id(DsgId) of
		#base_designation{name = DsgName} -> skip;
		_ -> DsgName = ""
	end,
	DsgName.

%% 将新数据移动到old部分,并保存old_rank
move_rank(State) ->
	#guild_race_rank_state{guild_rank_list = GuildRankList, member_rank_map = MemberRankMap} = State,
	%% 替换Guild old_rank
	F = fun(TGuildRank, TList) ->
		#guild_rank{guild_id = TGuildId, sum_power = NowSumPower, rank = NowRank} = TGuildRank,
		lib_guild_race_rank:db_update_guild_old_rank(TGuildId, NowRank, NowSumPower),
		lists:keystore(TGuildId, #guild_rank.guild_id, TList,
			TGuildRank#guild_rank{old_power = NowSumPower, old_rank = NowRank}
		)
	end,
	GuildRankList1 = lists:foldl(F, [], GuildRankList),
	MemberRankList = lists:flatten(maps:values(MemberRankMap)),
	%% 替换Member old_rank
	F1 = fun(TMemberRank, TMemberRankList) ->
	        #member_rank{role_id = TRoleId1, guild_id = TGuildId1, power = NowMemePower,
		        rank = NowMemRank, position = Position, live = Live, received_power = ReceivePower
	            ,received_live = ReceiveLive, received_captain_power = CaptainPower,
		        received_captain_live = CaptainLive
	        } = TMemberRank,
			lib_guild_race_rank:db_save_guild_race_rank_member(
				TRoleId1, TGuildId1, Position, NowMemePower, NowMemRank,
				Live, ReceivePower, ReceiveLive, CaptainPower, CaptainLive
			),
			lists:keystore(TRoleId1, #member_rank.role_id, TMemberRankList,
				TMemberRank#member_rank{old_power = NowMemePower, old_rank = NowMemRank, old_live = Live})
	     end,
	MemberRankList1 = lists:foldl(F1, [], MemberRankList),
	%% 重新组织数据
	F2 = fun(TMemberRank2, TMap) ->
			#member_rank{role_id = TRoleId2, guild_id = TGuildId2} = TMemberRank2,
			case maps:get(TGuildId2, TMap, []) of
				[_|_] = TMemberRankList2 ->
					NTMemberRankList2 = lists:keystore(TRoleId2, #member_rank.role_id, TMemberRankList2, TMemberRank2),
					maps:put(TGuildId2, NTMemberRankList2, TMap);
				_ ->
					NTMemberRankList2 = lists:keystore(TRoleId2, #member_rank.role_id, [], TMemberRank2),
					maps:put(TGuildId2, NTMemberRankList2, TMap)
			end end,
	MemberRankMap1 = lists:foldl(F2, #{}, MemberRankList1),
	%% Date: 2021-04-25  ps: 新增 替换Guild Live old_live
	F3 = fun(TGuildRank3, TList3) ->
		#guild_rank{guild_id = TGuildId3, sum_live = NowSumLive, live_rank = NowLiveRank} = TGuildRank3,
		lib_guild_race_rank:db_update_guild_race_rank_old_live(TGuildId3, NowSumLive),
		lists:keystore(TGuildId3, #guild_rank.guild_id, TList3,
			TGuildRank3#guild_rank{old_live = NowSumLive, old_live_rank = NowLiveRank}
		)
	    end,
	GuildRankList2 = lists:foldl(F3, [], GuildRankList1),
	NewState = State#guild_race_rank_state{
		guild_rank_list = GuildRankList2, member_rank_map = MemberRankMap1},
	NewState.

%% -------------------------------------------------------------------------------------------
%% @doc 扩容邮件 @end
%% 发送扩容成功邮件(0点给前3社团发，非0点只给新上榜前3社团发)
send_expand_success_mail(NewGuildList, UpGuildList, IsFirst) ->
	GuildList = case IsFirst of
					true -> NewGuildList;
					_ ->
						case utime:unixtime_to_localtime(utime:unixtime()) of
							{_, {0, _, _}} -> NewGuildList;
							_ -> UpGuildList
						end
	            end,
	TitleNum = 3316621, ContentNum = 3316622,
	GuildList =/= [] andalso
	mod_guild:apply_cast(?MODULE, send_expand_mail_core, [GuildList, TitleNum, ContentNum]).

%% 发送扩容失败邮件
send_expand_fail_mail(GuildList) ->
	TitleNum = 3316625, ContentNum = 3316626,
	mod_guild:apply_cast(?MODULE, send_expand_mail_core, [GuildList, TitleNum, ContentNum]).

%% 发送永久扩容邮件
send_expand_forever_mail(GuildList) ->
	TitleNum = 3316623, ContentNum = 3316624,
	mod_guild:apply_cast(?MODULE, send_expand_mail_core, [GuildList, TitleNum, ContentNum]).

send_expand_mail_core([], _TitleNum, _ContentNum) -> ok;
send_expand_mail_core([GuildId|T], TitleNum, ContentNum) ->
	MemberMap = lib_guild_data:get_guild_member_map(GuildId),
	F = fun(_K, #guild_member{position = Position, id = RoleId}, List) ->
		case lists:member(Position, [?POS_CHIEF, ?POS_DUPTY_CHIEF]) of
			true -> [RoleId|List];
			_ -> List
		end end,
	Captains = maps:fold(F, [], MemberMap),
	OpenDay = util:get_open_day(),
	AddNum =
	case data_guild_race_rank:get_guild_race_rank_expand_cfg(OpenDay) of
		ExpandNum when is_integer(ExpandNum) -> ExpandNum;
		_ ->
			data_guild_race_rank:get_guild_race_rank_expand_cfg(?DEFAULT_END_DAY)
	end,
	Title = utext:get(TitleNum), Content = utext:get(ContentNum, [AddNum]),
	lib_mail_api:send_sys_mail(Captains, ?MOD_AC_CUSTOM, ?CUSTOM_ACT_TYPE_GUILD_RACE_RANK, Title, Content, []),
	send_expand_mail_core(T, TitleNum, ContentNum).

%% -------------------------------------------------------------------------------------------
%% @doc 奖励领取情况 @end
reward_receive_status(RoleId, MyGuildId, RewardType, State) ->
	OpenDay = util:get_open_day(),
	#guild_race_rank_state{member_rank_map = MemberRankMap, role_guild_map = RoleGuildMap, guild_rank_list = GuildRankList} = State,
	RealGuildId = get_real_guild_id(RoleId, MyGuildId, RoleGuildMap),
	MemberRankList = maps:get(RealGuildId, MemberRankMap, []),
	PowerGuildList = [TGuildId1||#guild_rank{rank = Rank1, guild_id = TGuildId1}<-GuildRankList,lists:member(Rank1, ?GUILD_TOP_RANK)],
	LiveGuildList  = [TGuildId2||#guild_rank{live_rank = Rank2, guild_id = TGuildId2}<-GuildRankList,
		lists:member(Rank2, lists:seq(1, ?SEND_LIVE_REWARD_RANK_NEED))
	],
	IsPowerGuild = lists:member(RealGuildId, PowerGuildList),
	IsLiveGuild  = lists:member(RealGuildId, LiveGuildList),
	case lists:keyfind(RoleId, #member_rank.role_id, MemberRankList) of
		#member_rank{received_power = ReceivePower, received_live = ReceiveLive
			,received_captain_power = CaptainPower, received_captain_live = CaptainLive
			,position = Position
		} ->
			case OpenDay < ?REWARD_RECEIVE_DAY of
				true -> Status = 0;
				_ ->
					case RewardType of
						1 -> Status = case IsPowerGuild of
							              true ->
								              case ReceivePower of
									              0 -> ?CAN_RECEIVE_REWARD;
									              _ -> ?HAS_RECEIVE_REWARD
								              end;
							              _ ->
								              ?NOT_RECEIVE_REWARD
						              end;
						2 -> Status = case IsLiveGuild of
							              true ->
								              case ReceiveLive of
									              0 -> ?CAN_RECEIVE_REWARD;
									              _ -> ?HAS_RECEIVE_REWARD
								              end;
							              _ ->
								              ?NOT_RECEIVE_REWARD
						              end;
						3 -> Status = case IsPowerGuild of
							              true ->
								              case Position of
									              ?POS_CHIEF when CaptainPower == 0 ->
										              ?CAN_RECEIVE_REWARD;
									              ?POS_CHIEF ->
										              ?HAS_RECEIVE_REWARD;
									              _ ->
										              ?NOT_RECEIVE_REWARD
								              end;
							              _ ->
								              ?NOT_RECEIVE_REWARD
						              end;
						4 -> Status = case IsLiveGuild of
							              true ->
								              case Position of
									              ?POS_CHIEF when CaptainLive == 0 ->
										              ?CAN_RECEIVE_REWARD;
									              ?POS_CHIEF ->
										              ?HAS_RECEIVE_REWARD;
									              _ ->
										              ?NOT_RECEIVE_REWARD
								              end;
							              _ ->
								              ?NOT_RECEIVE_REWARD
						              end;
						_ ->
							Status = ?NOT_RECEIVE_REWARD
					end
			end,
			lib_server_send:send_to_uid(RoleId, pt_407, 40704, [RewardType, Status]);
		_ ->
			lib_server_send:send_to_uid(RoleId, pt_407, 40704, [RewardType, 0])
	end,
	ok.

%% @doc 领取各类奖励
%%      1. 必须要等到最后一次定时器结算之后才可以领取
%%      2. 第八天更换社团也不能领取奖励(因为新GuildId找不到对应的玩家数据)
%% @end
%% 领取战力榜奖励
receive_power_reward(RoleId, _GuildId, State) ->
	#guild_race_rank_state{member_rank_map = MemberRankMap, guild_rank_list = GuildRankList,
		role_guild_map = RoleGuildMap, ref = Ref
	} = State,
	GuildId = maps:get(RoleId, RoleGuildMap, 0),
	GuildList = [TGuildId||#guild_rank{rank = Rank, guild_id = TGuildId}<-GuildRankList,lists:member(Rank, ?GUILD_TOP_RANK)],
	case lists:member(GuildId, GuildList) of
		true when Ref == [] ->
			MemberRankList = maps:get(GuildId, MemberRankMap, []),
			NewMemberRankMap =
			case lists:keyfind(RoleId, #member_rank.role_id, MemberRankList) of
				#member_rank{received_power = ?NOT_RECEIVE_REWARD} = MemberRank ->
					db_update_guild_race_rank_member_received_power(RoleId, ?HAS_RECEIVE_REWARD),
					SendReward = case data_guild_race_rank:get_guild_race_rank_kv_cfg(common_reward) of
						             [_|_] = Reward -> Reward;
						             _ -> []
					             end,
					Produce = #produce{reward = SendReward, type = guild_race_power_reawrd},
					lib_goods_api:send_reward_with_mail(RoleId, Produce, ?MOD_GUILD),
					NewMemberRankList = lists:keystore(RoleId, #member_rank.role_id, MemberRankList,
						MemberRank#member_rank{received_power = ?HAS_RECEIVE_REWARD}
					),
					lib_server_send:send_to_uid(RoleId, pt_407, 40705, [?SUCCESS, 1]),
					maps:put(GuildId, NewMemberRankList, MemberRankMap);
				#member_rank{} ->
					lib_server_send:send_to_uid(RoleId, pt_407, 40705, [?ERRCODE(err407_has_received), 1]),
					MemberRankMap;
				_ ->
					lib_server_send:send_to_uid(RoleId, pt_407, 40705, [?ERRCODE(err407_cannot_receive), 1]),
					MemberRankMap
			end;
		_ ->
			lib_server_send:send_to_uid(RoleId, pt_407, 40705, [?ERRCODE(err407_cannot_receive), 1]),
			NewMemberRankMap = MemberRankMap
	end,
	State#guild_race_rank_state{member_rank_map = NewMemberRankMap}.

%% 领取活跃榜奖励
receive_live_reward(RoleId, _GuildId, State) ->
	#guild_race_rank_state{member_rank_map = MemberRankMap, guild_rank_list = GuildRankList,
		role_guild_map = RoleGuildMap, ref = Ref
	} = State,
	GuildId = maps:get(RoleId, RoleGuildMap, 0),
	GuildList = [
		TGuildId||#guild_rank{live_rank = Rank, guild_id = TGuildId}<-GuildRankList,
		lists:member(Rank, lists:seq(1, ?SEND_LIVE_REWARD_RANK_NEED))
	],
	case lists:member(GuildId, GuildList) of
		true when Ref == [] ->
			MemberRankList = maps:get(GuildId, MemberRankMap, []),
			NewMemberRankMap =
				case lists:keyfind(RoleId, #member_rank.role_id, MemberRankList) of
					#member_rank{received_live = ?NOT_RECEIVE_REWARD} = MemberRank ->
						db_update_guild_race_rank_member_received_live(RoleId, ?HAS_RECEIVE_REWARD),
						SendReward = case data_guild_race_rank:get_guild_race_rank_kv_cfg(active_common_reward) of
							             [_|_] = Reward -> Reward;
							             _ -> []
						             end,
						Produce = #produce{reward = SendReward, type = guild_race_live_reawrd},
						lib_goods_api:send_reward_with_mail(RoleId, Produce, ?MOD_GUILD),
						NewMemberRankList = lists:keystore(RoleId, #member_rank.role_id, MemberRankList,
							MemberRank#member_rank{received_live = ?HAS_RECEIVE_REWARD}
						),
						lib_server_send:send_to_uid(RoleId, pt_407, 40705, [?SUCCESS, 2]),
						maps:put(GuildId, NewMemberRankList, MemberRankMap);
					#member_rank{} ->
						lib_server_send:send_to_uid(RoleId, pt_407, 40705, [?ERRCODE(err407_has_received), 2]),
						MemberRankMap;
					_ ->
						lib_server_send:send_to_uid(RoleId, pt_407, 40705, [?ERRCODE(err407_cannot_receive), 2]),
						MemberRankMap
				end;
		_ ->
			lib_server_send:send_to_uid(RoleId, pt_407, 40705, [?ERRCODE(err407_cannot_receive), 2]),
			NewMemberRankMap = MemberRankMap
	end,
	State#guild_race_rank_state{member_rank_map = NewMemberRankMap}.

%% 领取战力榜团长专属奖励
receive_captain_power_reward(RoleId, _GuildId, State) ->
	#guild_race_rank_state{member_rank_map = MemberRankMap, guild_rank_list = GuildRankList,
		role_guild_map = RoleGuildMap, ref = Ref
	} = State,
	GuildId = maps:get(RoleId, RoleGuildMap, 0),
	GuildList = [TGuildId||#guild_rank{rank = Rank, guild_id = TGuildId}<-GuildRankList,lists:member(Rank, ?GUILD_TOP_RANK)],
	case lists:member(GuildId, GuildList) of
		true when Ref == [] ->
			MemberRankList = maps:get(GuildId, MemberRankMap, []),
			NewMemberRankMap =
				case lists:keyfind(RoleId, #member_rank.role_id, MemberRankList) of
					#member_rank{received_captain_power = ?NOT_RECEIVE_REWARD, position = 1} = MemberRank ->
						db_update_guild_race_rank_member_received_captain_power(RoleId, ?HAS_RECEIVE_REWARD),
						SendReward = case data_guild_race_rank:get_guild_race_rank_kv_cfg(power_chairman_reward) of
							             [_|_] = Reward -> Reward;
							             _ -> []
						             end,
						Produce = #produce{reward = SendReward, type = guild_race_captain_power_reawrd},
						lib_goods_api:send_reward_with_mail(RoleId, Produce, ?MOD_GUILD),
						NewMemberRankList = lists:keystore(RoleId, #member_rank.role_id, MemberRankList,
							MemberRank#member_rank{received_captain_power = ?HAS_RECEIVE_REWARD}
						),
						lib_server_send:send_to_uid(RoleId, pt_407, 40705, [?SUCCESS, 3]),
						maps:put(GuildId, NewMemberRankList, MemberRankMap);
					#member_rank{position = 1} ->
						lib_server_send:send_to_uid(RoleId, pt_407, 40705, [?ERRCODE(err407_has_received), 3]),
						MemberRankMap;
					#member_rank{position = Position} when Position =/= ?POS_CHIEF ->
						lib_server_send:send_to_uid(RoleId, pt_407, 40705, [?ERRCODE(err407_not_captain), 3]),
						MemberRankMap;
					_ ->
						lib_server_send:send_to_uid(RoleId, pt_407, 40705, [?ERRCODE(err407_cannot_receive), 3]),
						MemberRankMap
				end;
		_ ->
			lib_server_send:send_to_uid(RoleId, pt_407, 40705, [?ERRCODE(err407_cannot_receive), 3]),
			NewMemberRankMap = MemberRankMap
	end,
	State#guild_race_rank_state{member_rank_map = NewMemberRankMap}.

%% 领取活跃榜团长专属奖励
receive_captain_live_reward(RoleId, _GuildId, State) ->
	#guild_race_rank_state{member_rank_map = MemberRankMap, guild_rank_list = GuildRankList,
		role_guild_map = RoleGuildMap, ref = Ref
	} = State,
	GuildId = maps:get(RoleId, RoleGuildMap, 0),
	GuildList = [
		TGuildId||#guild_rank{live_rank = Rank, guild_id = TGuildId}<-GuildRankList,
		lists:member(Rank, lists:seq(1, ?SEND_LIVE_REWARD_RANK_NEED))
	],
	case lists:member(GuildId, GuildList) of
		true when Ref == [] ->
			MemberRankList = maps:get(GuildId, MemberRankMap, []),
			NewMemberRankMap =
				case lists:keyfind(RoleId, #member_rank.role_id, MemberRankList) of
					#member_rank{received_captain_live = ?NOT_RECEIVE_REWARD, position = 1} = MemberRank ->
						db_update_guild_race_rank_member_received_captain_live(RoleId, ?HAS_RECEIVE_REWARD),
						SendReward = case data_guild_race_rank:get_guild_race_rank_kv_cfg(active_chairman_reward) of
							             [_|_] = Reward -> Reward;
							             _ -> []
						             end,
						Produce = #produce{reward = SendReward, type = guild_race_captain_live_reawrd},
						lib_goods_api:send_reward_with_mail(RoleId, Produce, ?MOD_GUILD),
						NewMemberRankList = lists:keystore(RoleId, #member_rank.role_id, MemberRankList,
							MemberRank#member_rank{received_captain_live = ?HAS_RECEIVE_REWARD}
						),
						lib_server_send:send_to_uid(RoleId, pt_407, 40705, [?SUCCESS, 4]),
						maps:put(GuildId, NewMemberRankList, MemberRankMap);
					#member_rank{position = 1} ->
						lib_server_send:send_to_uid(RoleId, pt_407, 40705, [?ERRCODE(err407_has_received), 4]),
						MemberRankMap;
					#member_rank{position = Position} when Position =/= ?POS_CHIEF ->
						lib_server_send:send_to_uid(RoleId, pt_407, 40705, [?ERRCODE(err407_not_captain), 4]),
						MemberRankMap;
					_ ->
						lib_server_send:send_to_uid(RoleId, pt_407, 40705, [?ERRCODE(err407_cannot_receive), 4]),
						MemberRankMap
				end;
		_ ->
			lib_server_send:send_to_uid(RoleId, pt_407, 40705, [?ERRCODE(err407_cannot_receive), 4]),
			NewMemberRankMap = MemberRankMap
	end,
	State#guild_race_rank_state{member_rank_map = NewMemberRankMap}.

%% 活动第九天0点给玩家发放未领取奖励
send_not_received_reward(State) ->
	#guild_race_rank_state{member_rank_map = MemberRankMap, guild_rank_list = GuildRankList
	, guild_task = GuildTaskMap} = State,
	%% 1> 战力榜全员
	MemberRankMap1 = send_power_reward(MemberRankMap, GuildRankList),
	%% 2> 活跃榜全员
	MemberRankMap2 = send_live_reward(MemberRankMap1, GuildRankList),
	%% 3> 战力榜团长专属
	MemberRankMap3 = send_captain_power_reward(MemberRankMap2, GuildRankList),
	%% 4> 活跃榜团长专属
	MemberRankMap4 = send_captain_live_reward(MemberRankMap3, GuildRankList),
	%% 5> 团长任务奖励
	send_captain_task_reward(GuildTaskMap, GuildRankList),
	State#guild_race_rank_state{member_rank_map = MemberRankMap4}.

%% todo: 邮件和db存储延时
send_power_reward(MemberRankMap, GuildRankList) ->
	GuildList = [
		TGuildId||#guild_rank{rank = Rank, guild_id = TGuildId}<-GuildRankList,
		lists:member(Rank, lists:seq(1, ?SEND_POWER_REWARD_RANK_NEED))
	],
	%% 统一发放奖励
	SendReward = case data_guild_race_rank:get_guild_race_rank_kv_cfg(common_reward) of
		             [_|_] = Reward -> Reward;
		             _ -> []
	             end,
	Title = utext:get(3316611), Content = utext:get(3316612),
	MemFun = fun(GuildId, TMemMap) ->
		MemberList = maps:get(GuildId, TMemMap, []),
		RoleFun = fun(#member_rank{role_id = RoleId, received_power = ReceivePower} = MemberRank,
				{TRoleList, TMemberList}) ->
			case ReceivePower of
				?NOT_RECEIVE_REWARD ->
					TMemberList1 = lists:keystore(RoleId, #member_rank.role_id, TMemberList,
						MemberRank#member_rank{received_power = ?HAS_RECEIVE_REWARD}
					),
					{[RoleId|TRoleList], TMemberList1};
				_ ->
					{TRoleList, TMemberList}
			end end,
		{RoleIdList, NewMemberList} = lists:foldl(RoleFun, {[], MemberList}, MemberList),
		lib_mail_api:send_sys_mail(
			RoleIdList, ?MOD_AC_CUSTOM, ?CUSTOM_ACT_TYPE_GUILD_RACE_RANK, Title, Content, SendReward
		),
		db_update_roles_received_power(RoleIdList),
		maps:put(GuildId, NewMemberList, TMemMap)
	end,
	NewMemberRankMap = lists:foldl(MemFun, MemberRankMap, GuildList),
	NewMemberRankMap.

send_live_reward(MemberRankMap, GuildRankList) ->
	GuildList = [
		TGuildId||#guild_rank{live_rank = Rank, guild_id = TGuildId}<-GuildRankList,
		lists:member(Rank, lists:seq(1, ?SEND_LIVE_REWARD_RANK_NEED))
	],
	%% 统一发放奖励
	SendReward = case data_guild_race_rank:get_guild_race_rank_kv_cfg(active_common_reward) of
		             [_|_] = Reward -> Reward;
		             _ -> []
	             end,
	Title = utext:get(3316619), Content = utext:get(3316620),
	MemFun = fun(GuildId, TMemMap) ->
		MemberList = maps:get(GuildId, TMemMap, []),
		RoleFun = fun(#member_rank{role_id = RoleId, received_live = ReceiveLive} = MemberRank,
				{TRoleList, TMemberList}) ->
			case ReceiveLive of
				?NOT_RECEIVE_REWARD ->
					TMemberList1 = lists:keystore(RoleId, #member_rank.role_id, TMemberList,
						MemberRank#member_rank{received_live = ?HAS_RECEIVE_REWARD}
					),
					{[RoleId|TRoleList], TMemberList1};
				_ ->
					{TRoleList, TMemberList}
			end end,
		{RoleIdList, NewMemberList} = lists:foldl(RoleFun, {[], MemberList}, MemberList),
		lib_mail_api:send_sys_mail(
			RoleIdList, ?MOD_AC_CUSTOM, ?CUSTOM_ACT_TYPE_GUILD_RACE_RANK, Title, Content, SendReward
		),
		db_update_roles_received_live(RoleIdList),
		maps:put(GuildId, NewMemberList, TMemMap)
	end,
	NewMemberRankMap = lists:foldl(MemFun, MemberRankMap, GuildList),
	NewMemberRankMap.

send_captain_power_reward(MemberRankMap, GuildRankList) ->
	GuildList = [
		TGuildId||#guild_rank{rank = Rank, guild_id = TGuildId}<-GuildRankList,
		lists:member(Rank, lists:seq(1, ?SEND_POWER_REWARD_RANK_NEED))
	],
	%% 统一发放奖励
	SendReward = case data_guild_race_rank:get_guild_race_rank_kv_cfg(power_chairman_reward) of
		             [_|_] = Reward -> Reward;
		             _ -> []
	             end,
	Title = utext:get(3316615), Content = utext:get(3316616),
	MemFun = fun(GuildId, TMemMap) ->
		MemberList = maps:get(GuildId, TMemMap, []),
		RoleFun = fun(#member_rank{role_id = RoleId, received_captain_power = CaptainPower,
			position = Position} = MemberRank, {TRoleList, TMemberList}) ->
			case CaptainPower of
				?NOT_RECEIVE_REWARD when Position == ?POS_CHIEF ->
					TMemberList1 = lists:keystore(RoleId, #member_rank.role_id, TMemberList,
						MemberRank#member_rank{received_captain_power = ?HAS_RECEIVE_REWARD}
					),
					{[RoleId|TRoleList], TMemberList1};
				_ ->
					{TRoleList, TMemberList}
			end end,
		{RoleIdList, NewMemberList} = lists:foldl(RoleFun, {[], MemberList}, MemberList),
		lib_mail_api:send_sys_mail(
			RoleIdList, ?MOD_AC_CUSTOM, ?CUSTOM_ACT_TYPE_GUILD_RACE_RANK, Title, Content, SendReward
		),
		db_update_captains_received_power(RoleIdList),
		maps:put(GuildId, NewMemberList, TMemMap)
	end,
	NewMemberRankMap = lists:foldl(MemFun, MemberRankMap, GuildList),
	NewMemberRankMap.

send_captain_live_reward(MemberRankMap, GuildRankList) ->
	GuildList = [
		TGuildId||#guild_rank{live_rank = Rank, guild_id = TGuildId}<-GuildRankList,
		lists:member(Rank, lists:seq(1, ?SEND_LIVE_REWARD_RANK_NEED))
	],
	%% 统一发放奖励
	SendReward = case data_guild_race_rank:get_guild_race_rank_kv_cfg(active_chairman_reward) of
		             [_|_] = Reward -> Reward;
		             _ -> []
	             end,
	Title = utext:get(3316617), Content = utext:get(3316618),
	MemFun = fun(GuildId, TMemMap) ->
		MemberList = maps:get(GuildId, TMemMap, []),
		RoleFun = fun(#member_rank{role_id = RoleId, received_captain_live = CaptainLive,
			position = Position} = MemberRank, {TRoleList, TMemberList}) ->
			case CaptainLive of
				?NOT_RECEIVE_REWARD when Position == ?POS_CHIEF ->
					TMemberList1 = lists:keystore(RoleId, #member_rank.role_id, TMemberList,
						MemberRank#member_rank{received_captain_live = ?HAS_RECEIVE_REWARD}
					),
					{[RoleId|TRoleList], TMemberList1};
				_ ->
					{TRoleList, TMemberList}
			end end,
		{RoleIdList, NewMemberList} = lists:foldl(RoleFun, {[], MemberList}, MemberList),
		lib_mail_api:send_sys_mail(
			RoleIdList, ?MOD_AC_CUSTOM, ?CUSTOM_ACT_TYPE_GUILD_RACE_RANK, Title, Content, SendReward
		),
		db_update_captains_received_live(RoleIdList),
		maps:put(GuildId, NewMemberList, TMemMap)
	end,
	NewMemberRankMap = lists:foldl(MemFun, MemberRankMap, GuildList),
	NewMemberRankMap.

%% 只发奖，数据不修改？
send_captain_task_reward(GuildTaskMap, GuildRankList) ->
	Title = utext:get(3316627), Content = utext:get(3316628),
	MapF = fun(GuildId, TaskList) ->
		case lists:keyfind(GuildId, #guild_rank.guild_id, GuildRankList) of
			#guild_rank{captain_id = CaptainId, create_id = CreateId} ->
				IsCreater = CaptainId == CreateId;
			_ -> CaptainId = 0, IsCreater = false
		end,
		TaskF = fun(Task, TRewardList) ->
			case Task of
				#guild_race_rank_task{task_id = TaskId, status = ?CAN_RECEIVE_REWARD} ->
					case TaskId of
						1 when IsCreater == false -> TRewardList;
						_ ->
							case data_guild_race_rank:get_task(TaskId) of
								#base_guild_race_rank_task{reward = Reward} ->
									Reward ++ TRewardList;
								_ -> TRewardList
							end
					end;
				_ ->
					TRewardList
			end end,
		RewardList = lists:foldl(TaskF, [], TaskList),
		case CaptainId > 0 of
			true ->
				lib_mail_api:send_sys_mail(
					[CaptainId], ?MOD_AC_CUSTOM, ?CUSTOM_ACT_TYPE_GUILD_RACE_RANK, Title, Content, RewardList
				);
			_ -> ignore
		end
	end,
	maps:map(MapF, GuildTaskMap),
	ok.

%% ---------------------------- 数据库操作 -------------------------------
%% 社团榜相关
db_save_guild_race_rank(GuildId, GuildName, GuildLv, CaptainId, SumPower, OldPower, OldRank, SumLive, CreatId) ->
	NowTime = utime:unixtime(),
	db:execute(io_lib:format(?insert_guild_race_rank,
		[GuildId, GuildName, GuildLv, CaptainId, SumPower, OldPower, OldRank, SumLive, CreatId, NowTime]
	)).

db_select_guild_race_rank() ->
	db:get_all(io_lib:format(?select_guild_race_rank, [])).

db_delete_guild_race_rank(GuildId) ->
	db:execute(io_lib:format(?delete_guild_race, [GuildId])).

db_update_guild_race_rank_power(GuildId, Power) ->
	db:execute(io_lib:format(?update_guild_race_rank_power, [Power, GuildId])).

%% 活跃值
db_update_guild_race_rank_old_live(GuildId, OldLive) ->
	db:execute(io_lib:format(?update_guild_race_rank_old_live, [OldLive, GuildId])).

db_update_guild_name(GuildId, GuildName) ->
	db:execute(io_lib:format(?update_guild_race_rank_guild_name, [GuildName, GuildId])).

db_update_guild_lv(GuildId, GuildLv) ->
	db:execute(io_lib:format(?update_guild_race_rank_guild_lv, [GuildLv, GuildId])).

db_update_guild_race_rank_captain(GuildId, CaptainId) ->
	db:execute(io_lib:format(?update_guild_race_rank_captain, [CaptainId, GuildId])).

db_update_guild_old_rank(GuildId, OldRank, OldPower) ->
	db:execute(io_lib:format(?update_guild_race_rank_old_rank, [OldRank, OldPower, GuildId])).


%% 成员榜相关
db_save_guild_race_rank_member(RoleId, GuildId, Position, OldPower, OldRank,
		OldLive, PowerReward, LiveReward, CaptainPower, CaptainLive
) ->
	db:execute(io_lib:format(?insert_guild_race_rank_member,
		[RoleId, GuildId, Position, OldPower, OldRank, OldLive,
			PowerReward, LiveReward, CaptainPower, CaptainLive
		]
	)).

db_select_guild_race_rank_member() ->
	db:get_all(io_lib:format(?select_guild_race_rank_member, [])).

db_delete_guild_race_rank_member(RoleId) ->
	db:execute(io_lib:format(?delete_guild_race_rank_member, [RoleId])).

db_delete_guild_race_rank_guild(GuildId) ->
	db:execute(io_lib:format(?delete_guild_race_rank_guild, [GuildId])).

db_update_guild_race_rank_member_position(RoleId, Position) ->
	db:execute(io_lib:format(?update_guild_race_rank_member_position, [Position, RoleId])).

db_update_guild_race_rank_member_old_live(RoleId, OldLive) ->
	db:execute(io_lib:format(?update_guild_race_rank_member_old_live, [OldLive, RoleId])).

db_update_guild_race_rank_member_received_power(RoleId, ReceivedPower) ->
	db:execute(io_lib:format(?update_guild_race_rank_member_received_power, [ReceivedPower, RoleId])).

db_update_guild_race_rank_member_received_live(RoleId, ReceivedLive) ->
	db:execute(io_lib:format(?update_guild_race_rank_member_received_live, [ReceivedLive, RoleId])).

db_update_guild_race_rank_member_received_captain_power(RoleId, ReceiveCaptain) ->
	db:execute(io_lib:format(?update_guild_race_rank_member_received_captain_power, [ReceiveCaptain, RoleId])).

db_update_guild_race_rank_member_received_captain_live(RoleId, ReceiveCaptain) ->
	db:execute(io_lib:format(?update_guild_race_rank_member_received_captain_live, [ReceiveCaptain, RoleId])).

db_get_guild_captain(GuildId) ->
	db:get_row(io_lib:format(?select_guild_captain, [GuildId])).

db_update_roles_received_power(RoleIdList) ->
	case RoleIdList of
		[_|_] ->
			F = fun(RoleId, TList) ->
				Sql = io_lib:format(<<"~p">>,[RoleId]),
				[Sql|TList]
			    end,
			NewSQLs = lists:foldl(F, [], RoleIdList),
			NewValues = util:join_bitstring(NewSQLs, <<", ">>),
			BatchSql = io_lib:format(<<"update guild_race_rank_member set `received_power` = 2 where `role_id` in (~ts)">>, [NewValues]),
			db:execute(BatchSql);
		_ ->
			ignore
	end,
	ok.

db_update_roles_received_live(RoleIdList) ->
	case RoleIdList of
		[_|_] ->
			F = fun(RoleId, TList) ->
				Sql = io_lib:format(<<"~p">>,[RoleId]),
				[Sql|TList]
			    end,
			NewSQLs = lists:foldl(F, [], RoleIdList),
			NewValues = util:join_bitstring(NewSQLs, <<", ">>),
			BatchSql = io_lib:format(<<"update guild_race_rank_member set `received_live` = 2 where `role_id` in (~ts)">>, [NewValues]),
			db:execute(BatchSql);
		_ ->
			ignore
	end,
	ok.

db_update_captains_received_power(RoleIdList) ->
	case RoleIdList of
		[_|_] ->
			F = fun(RoleId, TList) ->
				Sql = io_lib:format(<<"~p">>,[RoleId]),
				[Sql|TList]
			    end,
			NewSQLs = lists:foldl(F, [], RoleIdList),
			NewValues = util:join_bitstring(NewSQLs, <<", ">>),
			BatchSql = io_lib:format(<<"update guild_race_rank_member set `received_captain_power` = 2 where `role_id` in (~ts)">>, [NewValues]),
			db:execute(BatchSql);
		_ ->
			ignore
	end,
	ok.

db_update_captains_received_live(RoleIdList) ->
	case RoleIdList of
		[_|_] ->
			F = fun(RoleId, TList) ->
				Sql = io_lib:format(<<"~p">>,[RoleId]),
				[Sql|TList]
			    end,
			NewSQLs = lists:foldl(F, [], RoleIdList),
			NewValues = util:join_bitstring(NewSQLs, <<", ">>),
			BatchSql = io_lib:format(<<"update guild_race_rank_member set `received_captain_live` = 2 where `role_id` in (~ts)">>, [NewValues]),
			db:execute(BatchSql);
		_ ->
			ignore
	end,
	ok.

db_save_guild_race_role(GuildId, RoleIdList) ->
	case RoleIdList of
		[_|_] ->
			F = fun(RoleId, TList) ->
				Sql = io_lib:format(?insert_guild_race_rank_role_value, [RoleId, GuildId]),
				[Sql|TList]
			    end,
			NewSQLs = lists:foldl(F, [], RoleIdList),
			NewValues = util:join_bitstring(NewSQLs, <<", ">>),
			BatchSql = io_lib:format(?insert_guild_race_rank_role, [NewValues]),
			db:execute(BatchSql);
		_ ->
			ignore
	end,
	ok.

db_select_guild_race_role() ->
	db:get_all(io_lib:format(?select_guild_race_rank_role, [])).