%%%----------------------------------------------------------------------
%%% desc    :社团跑环协助-答题
%%% module  :guild_run_assist_quiz.erl
%%% author  :hh
%%% time    :21/04/14
%%%----------------------------------------------------------------------

-module (guild_run_assist_quiz).

-include ("predefine.hrl").
-include ("server.hrl").
-include ("guild_run_assist.hrl").
-include ("errcode.hrl").
-include ("figure.hrl").
-include ("common.hrl").
-include ("def_fun.hrl").

-export ([
    mgr_handle_assist_event/2
    ,role_handle_assist_event/3
    ]).

-export ([role_add_run_assist/3]).

-export ([
    get_quiz/2
    ,answer/3
    ,role_fin_run_assist/4
    ,active_quit_quiz/1
    ,relogin_notice/3
    ,role_expire_check/4
    ,role_quiz_expire_account/4
    ]).

-define (CAN_GET_QUIZ, 0).
-define (ANSWERING,    1).

%% 有人接单
mgr_handle_assist_event({after_take_run_assist, [RoleId, GuildId, Sid]}, State) ->
    lib_player:apply_cast(RoleId, ?APPLY_CAST_STATUS, ?MODULE, role_add_run_assist, [GuildId, Sid]),
    State;

mgr_handle_assist_event({after_fin_run_assist, [RoleId, GuildId, Sid, FinType]}, State) ->
    lib_player:apply_cast(RoleId, ?APPLY_CAST_STATUS, ?MODULE, role_fin_run_assist, [GuildId, Sid, FinType]),
    State;

mgr_handle_assist_event(_Msg, State) ->
    State.

role_handle_assist_event(Player, expire_cancel_run_asist, _Data) ->
    #player_status{sid = Sid, role_guild_run_assist = RoleRunAssist} = Player,
    #role_guild_run_assist{extra_data = ExtraData} = RoleRunAssist,
    NewExtraData = maps:remove(?GUILD_RUN_ASSIST_QUIZ, ExtraData),
    NewPlayer = Player#player_status{role_guild_run_assist = RoleRunAssist#role_guild_run_assist{extra_data = NewExtraData}},
    {ok, BinData} = pt_417:write(41703, [?FAIL]),
    lib_server_send:send_to_sid(Sid, BinData),
    NewPlayer;

role_handle_assist_event(Player, _Event, _Data) ->
    Player.

role_add_run_assist(Player, _GuildId, SupportId) ->
    #player_status{role_guild_run_assist = RoleRunAssist} = Player,
    #role_guild_run_assist{extra_data = ExtraData} = RoleRunAssist,
    QuizResult = #{success => [], fail => [], now_quiz_id => 0, state => ?CAN_GET_QUIZ},
    NewExtraData = maps:put(?GUILD_RUN_ASSIST_QUIZ, QuizResult, ExtraData),
    NewRoleAssist = RoleRunAssist#role_guild_run_assist{res_sid = SupportId, extra_data = NewExtraData},
    NewPlayer = Player#player_status{role_guild_run_assist = NewRoleAssist},
    {ok, NewPlayer}.

role_fin_run_assist(Player, _GuildId, SupportId, _FinType) ->
    #player_status{role_guild_run_assist = RoleRunAssist} = Player,
    #role_guild_run_assist{res_sid = ResSupportId, extra_data = ExtraData} = RoleRunAssist,
    if SupportId == ResSupportId ->
            NewExtraData = maps:remove(?GUILD_RUN_ASSIST_QUIZ, ExtraData),
            NewRoleAssist = RoleRunAssist#role_guild_run_assist{res_sid = 0, extra_data = NewExtraData},
            {ok, Player#player_status{role_guild_run_assist = NewRoleAssist}};
        true ->
            ok
    end.

%% 获取题目
get_quiz(RoleLv, QuizResult) ->
    SuccessRet = maps:get(success, QuizResult, []),
    FailRet = maps:get(fail, QuizResult, []),
    State = maps:get(state, QuizResult, false),
    FailNum = length(FailRet),
    SuccessNum = length(SuccessRet),
    [TotalNum, NeedSuccess] = data_guild_run_assist:get_kv(answer_times),
    FailLimit = TotalNum - NeedSuccess,
    Answered = SuccessNum + FailNum,
    if 
        Answered >= TotalNum ->
            {false, ?ERRCODE(err417_quiz_success)};
        SuccessNum >= NeedSuccess ->
            {false, ?ERRCODE(err417_quiz_success)};
        FailNum > FailLimit ->
            {false, ?ERRCODE(err417_quiz_fail)};
        State == false orelse State == ?ANSWERING ->
            {false, ?ERRCODE(err417_in_quiz)};
        true ->
            AllQuizId = data_guild_run_assist:get_all_quiz(),
            AllQuizId1 = AllQuizId -- SuccessRet,
            AllQuizId2 = calc_access_quiz(RoleLv, AllQuizId1 -- FailRet, AllQuizId),
            RandQuizId = urand:list_rand(AllQuizId2),
            NewQuizResult = maps:put(now_quiz_id, RandQuizId, QuizResult),
            NewQuizResult1 = maps:put(state, ?ANSWERING, NewQuizResult),
            {ok, length(SuccessRet) + length(FailRet) + 1, RandQuizId, NewQuizResult1}
    end.

calc_access_quiz(RoleLv, RestQuiz, AllQuizId) ->
    case lists:filter(fun(QuizId) -> 
        CfgLv = data_guild_run_assist:get_quiz_lv(QuizId),
        RoleLv >= CfgLv
    end, RestQuiz) of
        [] ->
            lists:filter(fun(QuizIdX) -> 
                CfgLv = data_guild_run_assist:get_quiz_lv(QuizIdX),
                RoleLv >= CfgLv
            end, AllQuizId);
        Ret ->
            Ret
    end.

answer(Player, QuizId, Answer) ->
    #player_status{id = RoleId, sid = Sid, figure = #figure{guild_id = GuildId}, role_guild_run_assist = RoleRunAssist} = Player,
    #role_guild_run_assist{res_sid = SupportId, extra_data = ExtraData} = RoleRunAssist,
    QuizResult = maps:get(?GUILD_RUN_ASSIST_QUIZ, ExtraData),
    SuccessRet = maps:get(success, QuizResult, []),
    FailRet = maps:get(fail, QuizResult, []),
    State = maps:get(state, QuizResult, false),
    FailNum = length(FailRet),
    SuccessNum = length(SuccessRet),
    [TotalNum, NeedSuccess] = data_guild_run_assist:get_kv(answer_times),
    FailLimit = TotalNum - NeedSuccess,
    Answered = SuccessNum + FailNum,
    if 
        Answered >= TotalNum ->
            lib_server_send:send_to_sid(Sid, pt_417, 41702, [?ERRCODE(err417_quiz_success), QuizId, Answer, SuccessNum]);
        SuccessNum >= NeedSuccess ->
            lib_server_send:send_to_sid(Sid, pt_417, 41702, [?ERRCODE(err417_quiz_success), QuizId, Answer, SuccessNum]);
        FailNum > FailLimit ->
            lib_server_send:send_to_sid(Sid, pt_417, 41702, [?ERRCODE(err417_quiz_fail), QuizId, Answer, SuccessNum]);
        State == false orelse State =/= ?ANSWERING ->
            lib_server_send:send_to_sid(Sid, pt_417, 41702, [?ERRCODE(err417_quiz_error), QuizId, Answer, SuccessNum]);
        true ->
            CorrectAnswer = data_guild_run_assist:get_quiz_answer(QuizId),
            AnswerRet =
            if CorrectAnswer == Answer ->
                    NewSuccessRet = [QuizId|SuccessRet],
                    NewFailRet = FailRet,
                    NewSuccessLen = length(NewSuccessRet),
                    % IsOver = NewSuccessLen + length(NewFailRet) >= TotalNum,
                    IsOver = NewSuccessLen >= NeedSuccess,
                    ResultRet = ?IF(NewSuccessLen >= NeedSuccess, 0, 1),
                    {?SUCCESS, ResultRet, IsOver};
                true ->
                    NewSuccessRet = SuccessRet,
                    NewFailRet = [QuizId|FailRet],
                    NewFailLen = length(NewFailRet),
                    % IsOver = length(NewSuccessRet) + NewFailLen >= TotalNum,
                    IsOver = NewFailLen > FailLimit,
                    ResultRet = ?IF(length(NewSuccessRet) >= NeedSuccess, 0, 1),
                    {?FAIL, ResultRet, IsOver}
            end,
            QuizResult1 = maps:put(success, NewSuccessRet, QuizResult),
            QuizResult2 = maps:put(fail, NewFailRet, QuizResult1),
            QuizResult3 = maps:put(state, ?CAN_GET_QUIZ, QuizResult2),
            NewExtraData = maps:put(?GUILD_RUN_ASSIST_QUIZ, QuizResult3, ExtraData),
            NewRoleAssist = RoleRunAssist#role_guild_run_assist{extra_data = NewExtraData},
            NewPlayer = Player#player_status{role_guild_run_assist = NewRoleAssist},
            case AnswerRet of
                {Errcode, FinishType, true} ->
                    {ok, BinData1} = pt_417:write(41702, [Errcode, QuizId, Answer, length(NewSuccessRet)]),
                    guild_run_assist:fin_run_assist(RoleId, GuildId, SupportId, ?GUILD_RUN_ASSIST_QUIZ, FinishType),
                    if FinishType == 0 ->
                            {ok, BinData2} = pt_417:write(41703, [?SUCCESS]);
                        true ->
                            {ok, BinData2} = pt_417:write(41703, [?FAIL])
                    end,
                    lib_server_send:send_to_sid(Sid, <<BinData1/binary, BinData2/binary>>);
                {Errcode, _, false} ->
                    lib_server_send:send_to_sid(Sid, pt_417, 41702, [Errcode, QuizId, Answer, length(NewSuccessRet)])
            end,
            {ok, NewPlayer}
    end.

active_quit_quiz(Player) ->
    #player_status{id = RoleId, sid = Sid, figure = #figure{guild_id = GuildId}, role_guild_run_assist = RoleRunAssist} = Player,
    #role_guild_run_assist{res_sid = SupportId, extra_data = ExtraData} = RoleRunAssist,
    QuizResult = maps:get(?GUILD_RUN_ASSIST_QUIZ, ExtraData),
    State = maps:get(state, QuizResult, false),
    if
        State == ?CAN_GET_QUIZ orelse State == ?ANSWERING ->
            guild_run_assist:fin_run_assist(RoleId, GuildId, SupportId, ?GUILD_RUN_ASSIST_QUIZ, 1),
            lib_server_send:send_to_sid(Sid, pt_417, 41704, [?SUCCESS]),
            ok;
        true ->
            lib_server_send:send_to_sid(Sid, pt_417, 41704, [?ERRCODE(err417_operation_fail)]),
            ok
    end.

relogin_notice(RoleId, ResSid, QuizResult) ->
    SuccessRet = maps:get(success, QuizResult, []),
    FailRet = maps:get(fail, QuizResult, []),
    QuizId = maps:get(now_quiz_id, QuizResult, 0),
    Answered = length(SuccessRet) + length(FailRet),
    Index = Answered + 1,
    lib_server_send:send_to_uid(RoleId, pt_417, 41705, [QuizId, Index, ResSid, length(SuccessRet)]),
    ok.

role_expire_check(ResRoles, AssistType, GuildId, Sid) ->
    lists:map(fun(RoleId) -> 
        case lib_player:is_online_global(RoleId) of
            false ->
                case erlang:erase(?DICT_GUILD_RUN_ASSIST(RoleId)) of
                    {GuildId, Sid, RoleAssistData} ->
                        offline_role_expire_quiz_logic(AssistType, GuildId, RoleId, Sid, RoleAssistData);
                    _ -> 
                        skip
                end;
            _ -> 
                lib_player:apply_cast(RoleId, ?APPLY_CAST_STATUS, ?MODULE, role_quiz_expire_account, [AssistType, GuildId, Sid])
        end
    end, ResRoles).

offline_role_expire_quiz_logic(AssistType, GuildId, RoleId, Sid, ExtraData) ->
    QuizResult = maps:get(?GUILD_RUN_ASSIST_QUIZ, ExtraData, #{}),
    SuccessRet = maps:get(success, QuizResult, []),
    SuccessNum = length(SuccessRet),
    [_TotalNum, NeedSuccess] = data_guild_run_assist:get_kv(answer_times),
    FinType =
    if SuccessNum >= NeedSuccess -> 0;
        true -> 1
    end,
    guild_run_assist:quiz_expire_account(AssistType, GuildId, RoleId, Sid, FinType),
    ok.

role_quiz_expire_account(Player, AssistType, GuildId, Sid) ->
    #player_status{id = RoleId, role_guild_run_assist = RoleRunAssist} = Player,
    #role_guild_run_assist{res_sid = ResSid, extra_data = ExtraData} = RoleRunAssist,
    if
        ResSid == Sid ->
            QuizResult = maps:get(?GUILD_RUN_ASSIST_QUIZ, ExtraData),
            SuccessRet = maps:get(success, QuizResult, []),
            SuccessNum = length(SuccessRet),
            [_TotalNum, NeedSuccess] = data_guild_run_assist:get_kv(answer_times),
            FinType =
            if SuccessNum >= NeedSuccess -> 0;
                true -> 1
            end,
            if FinType == 0 ->
                    {ok, BinData2} = pt_417:write(41703, [?SUCCESS]);
                true ->
                    {ok, BinData2} = pt_417:write(41703, [?FAIL])
            end,
            lib_server_send:send_to_uid(RoleId, BinData2),
            guild_run_assist:quiz_expire_account(AssistType, GuildId, RoleId, Sid, FinType),
            {ok, Player};
        true ->
            {ok, Player}
    end.