%% -------------------------------------------
%% desc         :守卫信标历史最佳记录展示
%% module       :guard_dun_assist.erl
%% author       :hh
%% time         :20/11/30
%% -------------------------------------------

-module (guard_dun_assist_mgr).

-behaviour (gen_server).

-export ([
    start_link/0
    ,handle_call/3
    ,handle_cast/2
    ,handle_info/2
    ,terminate/2
    ,code_change/3
    ]).

-export ([
    init/1
    ,upload_role_figure_info/6      %% 更新外观数据
    ,update_guard_dun_pass_log/3    %% 更新通关历史记录
    ,get_role_figure_info/3         %% 获取外观数据
    ,get_guard_dun_pass_log/3       %% 获取通关记录
    ,get_guard_dun_pass_reward/3    %% 获取全服首通奖励

    ,query_guard_dun_pass_reward/3
    ]).

-export([
    role_get_guard_dun_pass_reward/2
    ]).

-define (DELAY_INIT_TIME,           5000).
-define (DELAY_FIGURE_INIT_TIME,    600000).

-include ("dungeon.hrl").
-include ("figure.hrl").
-include ("dun_guard.hrl").
-include ("predefine.hrl").
-include ("def_module.hrl").
-include ("errcode.hrl").
-include ("server.hrl").
-include ("common.hrl").

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

init([]) ->
    erlang:send_after(?DELAY_INIT_TIME, self(), {init}),
    {ok, #guard_assist_state{}}.

%% 更新外观数据
upload_role_figure_info(FigureType, DunId, RoleId, RoleFigure, ServerId, ServerNum) ->
    gen_server:cast(?MODULE, {upload_role_figure_info, FigureType, DunId, RoleId, RoleFigure, ServerId, ServerNum}).

%% 更新通关历史记录
update_guard_dun_pass_log(DunId, PassTime, RoleList) ->
    gen_server:cast(?MODULE, {update_guard_dun_pass_log, DunId, PassTime, RoleList}).

%% 获取通关记录
get_guard_dun_pass_log(Node, Sid, DunId) ->
    gen_server:cast(?MODULE, {get_guard_dun_pass_log, Node, Sid, DunId}).

%% 获取全服首通奖励
get_guard_dun_pass_reward(Node, RoleId, DunId) ->
    gen_server:cast(?MODULE, {get_guard_dun_pass_reward, Node, RoleId, DunId}).

%% 查询副本首通奖励领取
query_guard_dun_pass_reward(Node, RoleId, DunCounts) ->
    gen_server:cast(?MODULE, {query_guard_dun_pass_reward, Node, RoleId, DunCounts}).

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

handle_cast(Msg, State) ->
    try
        do_handle_cast(Msg, State)
    catch _:_Error ->
        io:format("handle_cast Msg:~p, Error:~p, ~p~n", [Msg, _Error, erlang:get_stacktrace()]),
        {noreply, State}
    end.

handle_info(Msg, State) ->
    try
        do_handle_info(Msg, State)
    catch _:_Error ->
        io:format("[~p]~nhandle_info Msg:~p~n Error:~p~n ~p~n", [erlang:localtime(), Msg, _Error, erlang:get_stacktrace()]),
        {noreply, State}
    end.

do_handle_cast({upload_role_figure_info, FigureType, DunId, RoleId, RoleFigure, ServerId, ServerNum}, State) ->
    #guard_assist_state{guard_pass_history = GuardPassLogs} = State,
    if FigureType == guard_pass_log ->
            NewGuardPassLogs =
            case lists:keyfind(DunId, #guard_pass_log.dun_id, GuardPassLogs) of
                GuardLog = #guard_pass_log{role_list = RoleList} ->
                    NewRoleList =
                    case lists:keyfind(RoleId, #guard_team_role.role_id, RoleList) of
                        Role = #guard_team_role{} ->
                            lists:keystore(RoleId, #guard_team_role.role_id, RoleList, Role#guard_team_role{figure = RoleFigure, server_id = ServerId, server_num = ServerNum});
                        _ ->
                            RoleList
                    end,
                    lists:keystore(DunId, #guard_pass_log.dun_id, GuardPassLogs, GuardLog#guard_pass_log{role_list = NewRoleList});
                _ ->
                    GuardPassLogs
            end,
            NewState = State#guard_assist_state{guard_pass_history = NewGuardPassLogs};
        true ->
            NewState = State
    end,
    {noreply, NewState};

do_handle_cast({update_guard_dun_pass_log, DunId, PassTime, RoleList}, State) ->
    #guard_assist_state{guard_pass_history = GuardPassLogs} = State,
    case lists:keyfind(DunId, #guard_pass_log.dun_id, GuardPassLogs) of
        #guard_pass_log{pass_time = _MinPassTime} ->
            NewState = State;
        _ ->
            RoleList1 = lists:foldl(fun({RoleId, Figure, ServerId, ServerNum}, Acc) -> 
                [#guard_team_role{role_id = RoleId, figure = Figure, server_id = ServerId, server_num = ServerNum}|Acc]
            end, [], RoleList),
            NewGuardLog = #guard_pass_log{dun_id = DunId, pass_time = PassTime, role_list = RoleList1},
            db_update_guard_pass_log(NewGuardLog),
            NewGuardPassLogs = lists:keystore(DunId, #guard_pass_log.dun_id, GuardPassLogs, NewGuardLog),
            NewState = State#guard_assist_state{guard_pass_history = NewGuardPassLogs}
    end,
    {noreply, NewState};

%% 获取通关记录
do_handle_cast({get_guard_dun_pass_log, Node, Sid, DunId}, State) ->
    #guard_assist_state{guard_pass_history = GuardPassLogs} = State,
    GuardPassLogInfos = pack_guard_dun_pass_log(DunId, GuardPassLogs),
    {ok, BinData} = pt_611:write(61105, [GuardPassLogInfos]),
    lib_server_send:send_to_sid(Node, Sid, BinData),
    {noreply, State};

%% 获取全服首通奖励
do_handle_cast({get_guard_dun_pass_reward, Node, RoleId, DunId}, State) ->
    #guard_assist_state{guard_pass_history = GuardPassLogs} = State,
    case lists:keyfind(DunId, #guard_pass_log.dun_id, GuardPassLogs) of
        #guard_pass_log{} -> % Node, PlayerPid, CastType, HandleOffline, Moudle, Method, Args
            lib_player:apply_cast(Node, RoleId, ?APPLY_CAST_SAVE, ?NOT_HAND_OFFLINE, ?MODULE, role_get_guard_dun_pass_reward, [DunId]);
        _ ->
            {ok, BinData} = pt_611:write(61106, [?ERRCODE(err215_have_not_pass_dun), DunId]),
            lib_server_send:send_to_uid(Node, RoleId, BinData)
    end,
    {noreply, State};

do_handle_cast({query_guard_dun_pass_reward, Node, RoleId, DunCounts}, State) ->
    #guard_assist_state{guard_pass_history = GuardPassLogs} = State,
    RoleDunInfos = lists:foldl(fun({DunId, Count}, Acc) -> 
            case lists:keyfind(DunId, #guard_pass_log.dun_id, GuardPassLogs) of
                #guard_pass_log{} ->
                    if Count == 0 -> [{DunId, 1}|Acc];
                        true -> [{DunId, 2}|Acc]
                    end;
                _ ->
                    [{DunId, 0}|Acc]
            end
     end, [], DunCounts),
    {ok, BinData} = pt_611:write(61108, [RoleDunInfos]),
    lib_server_send:send_to_uid(Node, RoleId, BinData),
    {noreply, State};

do_handle_cast(_Msg, State) ->
    {noreply, State}.

do_handle_info({init}, State) ->
    #guard_assist_state{map = Map} = State,
    PassLog = 
    case db:get_all(?SQL_SELECT_GUARD_PASS_LOG, []) of
        Data = [_|_] ->
            change_data_format_1(Data);
        _ ->
            []
    end,
    NewState  = State#guard_assist_state{guard_pass_history = PassLog},
    Ref       = erlang:send_after(?DELAY_FIGURE_INIT_TIME, self(), {figure_init}),
    NewMap    = maps:put(figure_init, Ref, Map),
    NewState1 = NewState#guard_assist_state{map = NewMap},
    {noreply, NewState1};

do_handle_info({figure_init}, State) ->
    #guard_assist_state{guard_pass_history = PassLog, map = Map} = State,
    %% 检查更新最快通关记录的外观数据
    spawn(fun() ->
        lists:map(fun(#guard_pass_log{dun_id = DunId, role_list = RoleList}) -> 
            timer:sleep(urand:rand(1000, 3000)),
            lists:map(fun(#guard_team_role{role_id = RoleId, server_id = ServerId, figure = Figure}) ->
                if 
                    is_record(Figure, figure) ->
                        skip;
                    true -> 
                        NowServer = clusters_center:find_now_server_id(ServerId),
                        clusters_center:apply_cast(NowServer, ?MODULE, get_role_figure_info, [guard_pass_log, DunId, RoleId])
                end
            end, RoleList)
        end, PassLog)
    end),
    Ref = erlang:send_after(?DELAY_FIGURE_INIT_TIME, self(), {figure_init}),
    NewMap = maps:put(figure_init, Ref, Map),
    NewState = State#guard_assist_state{map = NewMap},
    {noreply, NewState};

do_handle_info(_Msg, State) ->
    {noreply, State}.

terminate(_Reason, _State) ->
    ok.

code_change(_OldVsn, _State, _Extra) ->
    ok.


change_data_format_1(Data) ->
    lists:foldl(fun([DunId, PassTime, TeamMatesBin], Acc) ->
         TeamMates = util:bitstring_to_term(TeamMatesBin),
         NewTeamMates = lists:map(fun({RoleId, ServerId, ServerNum}) -> 
            #guard_team_role{role_id = RoleId, server_id = ServerId, server_num = ServerNum}
         end, TeamMates),
        [#guard_pass_log{dun_id = DunId, pass_time = PassTime, role_list = NewTeamMates}|Acc]
    end, [], Data).

%% 目标服获取对应玩家外观数据缓存
get_role_figure_info(FigureType, DunId, RoleId) ->
    RoleFigure = lib_role:get_role_figure(RoleId),
    ServerId    = config:get_server_id(),
    ServerNum   = config:get_server_num(),
    clusters_node:apply_cast(?MODULE, upload_role_figure_info, [FigureType, DunId, RoleId, RoleFigure, ServerId, ServerNum]).

%% 更新通关记录
db_update_guard_pass_log(GuardLog) ->
    #guard_pass_log{
        dun_id = DunId,
        pass_time = PassTime,
        role_list = RoleList
    } = GuardLog,
    NewRoleList = [{RoleId, ServerId, ServerNum} || #guard_team_role{role_id = RoleId, server_id = ServerId, server_num = ServerNum} <- RoleList],
    db:execute(?SQL_REPLACE_GUARD_PASS_LOG, [DunId, PassTime, util:term_to_bitstring(NewRoleList)]),
    ok.

role_get_guard_dun_pass_reward(Player, DunId) ->
    #player_status{id = RoleId, sid = Sid} = Player,
    lib_counter:set_count(RoleId, ?MOD_DUN_MULTI, 3, DunId, 1),
    Rewards = data_dungeon_special:get(9, guard_dun_pass_reward),
    NewPlayer = lib_goods_api:send_reward(Player, Rewards, guard_dun_pass_reward),
    lib_server_send:send_to_sid(Sid, pt_611, 61106, [?SUCCESS, DunId]),
    {ok, NewPlayer}.

%% 打包61105协议数据
pack_guard_dun_pass_log(DunId, Logs) ->
    case lists:keyfind(DunId, #guard_pass_log.dun_id, Logs) of
        #guard_pass_log{pass_time = PassTime, role_list = RoleList} ->
            RoleInfos = pack_log_role(RoleList),
            [{DunId, RoleInfos, PassTime}];
        _ ->
            if DunId == 0 ->
                    lists:foldl(fun(#guard_pass_log{dun_id = DunIdX, pass_time = PassTimeX, role_list = RoleListX}, Acc) -> 
                        RoleInfosX = pack_log_role(RoleListX),
                        [{DunIdX, RoleInfosX, PassTimeX}|Acc]
                    end, [], Logs);
                true ->
                    [{DunId, [], 0}]
            end
    end.

pack_log_role(RoleList) ->
    lists:foldl(fun(Role, Acc) -> 
        #guard_team_role{
            role_id = RoleId, figure = Figure,
            server_num = ServerNum
        } = Role,
        case Figure of
            #figure{} -> Figure1 = Figure;
            _ -> Figure1 = #figure{}
        end,
        [{RoleId, Figure1, ServerNum}|Acc]
    end, [], RoleList).