%%%-------------------------------------------------------------------
%%% author : ljy
%%% desc   : 日常任务触发-协助副本
%%% Time   : 2021.04.13
%%%-------------------------------------------------------------------
-module(lib_dungeon_help).

-include("dungeon.hrl").
-include("server.hrl").
-include("figure.hrl").
-include("guild.hrl").
-include("attr.hrl").
-include("common.hrl").
-include("mon.hrl").
-include("guild_run_assist.hrl").
-include("predefine.hrl").
-include("scene.hrl").
-include("errcode.hrl").

%%%% 副本分发函数
-export([
    check_extra/2
    , get_start_dun_args/4
    , dispatch_dun_event/2
    , handle_dungeon_result/1

]).

-export([
    mon_born_callback/3
    , dungeon_born_notice/2
    , after_ask_for_support/4
    , role_handle_assist_event/3
    , mgr_handle_assist_event/2
    , handle_assist_event/5
    , notice_task_result/1
    , enter_dun_scene/2
    , recovery_mon_hp/1
    , fin_run_assist/1
    , player_attr_switch_mon_attr/4
]).


%% 检查是否可进入,是否接有击杀boss任务
check_extra(Player, _Dun) ->
    #player_status{role_guild_run_assist = RoleGuildRunAssist} = Player,
    #role_guild_run_assist{extra_data = ExtraMap} = RoleGuildRunAssist,
    case maps:get(?GUILD_RUN_ASSIST_BOSS, ExtraMap, []) of
        [_, _, _] -> true;
        _ -> {false, ?ERRCODE(err417_not_in_guild_run_assist)}
    end.

get_start_dun_args(Player, _DunRole, _DunCfg, _OptionType) ->
    #player_status{guild = Guild, role_guild_run_assist = RoleGuildRunAssist} = Player,
    #status_guild{id = GuildId} = Guild,
    #role_guild_run_assist{res_sid = SupportId, extra_data = ExtraMap} = RoleGuildRunAssist,
    [MonId, _, BaseAttr] = maps:get(?GUILD_RUN_ASSIST_BOSS, ExtraMap, []),
    [{typical_data, [{mon_attr, BaseAttr}, {mon_id, MonId}, {guild_id, GuildId}, {res_sid, SupportId}]}].

%% 怪物进程回调-出生通知
mon_born_callback(init, Minfo, [DunPid]) ->
    #scene_object{id = MonId, aid = MonPid} = Minfo,
    gen_server:cast(DunPid, {apply, ?MODULE, dungeon_born_notice, [MonPid, MonId]}).

dungeon_born_notice(State, [MonPid, MonId]) ->
    #dungeon_state{typical_data = TypicalData} = State,
    NTypicalData = maps:put(mon_pid, {MonPid, MonId}, TypicalData),
    State#dungeon_state{typical_data = NTypicalData}.

after_ask_for_support(RoleId, GuildId, {Module, SubModule, AutoId, TeamId, TeamLeaderName, Map}, GameInfo) ->
    GuildMemberMap = lib_guild_data:get_guild_member_map(GuildId),
    GuildMembers = maps:values(GuildMemberMap),
    % 战力排序
    F = fun(GuildMemberA, GuildMemberB) ->
        #guild_member{combat_power = CombatPowerA} = GuildMemberA,
        #guild_member{combat_power = CombatPowerB} = GuildMemberB,
        CombatPowerA > CombatPowerB
        end,
    GuildListSort = lists:sort(F, GuildMembers),
    Num = length(GuildListSort),
    GuildMember =
        if
            Num >= 10 ->
                lists:nth(10, GuildListSort);
            true -> lists:last(GuildListSort)
        end,
    #guild_member{id = GuildRoleId} = GuildMember,
    Pid = misc:get_player_process(GuildRoleId),
    case misc:is_process_alive(Pid) of
        true ->
            lib_player:apply_cast(
                Pid, ?APPLY_CAST_STATUS, ?MODULE, player_attr_switch_mon_attr, [RoleId, {Module, SubModule, AutoId, TeamId, TeamLeaderName, Map}, GameInfo]);
        _ ->
            PsM = lib_offline_api:get_player_info(GuildMember#guild_member.id, all),
            player_attr_switch_mon_attr(PsM, RoleId, {Module, SubModule, AutoId, TeamId, TeamLeaderName, Map}, GameInfo)
    end.


player_attr_switch_mon_attr(Player, OtherRoleId, {Module, SubModule, AutoId, TeamId, TeamLeaderName, Map}, GameInfo) ->
    #player_status{battle_attr = BattleAttr} = Player,
    #battle_attr{attr = Attr} = BattleAttr,
    {MonPower, DummyAttr} = calc_mon_power(Attr),
    BossList = data_guild_run_assist:get_kv(boss_list),
    MonId = urand:list_rand(BossList),
    [DunId | _] = data_dungeon:get_ids_by_type(?DUNGEON_TYPE_HELP),
    Map1 = maps:put(mon_id, MonId, Map),
    Map2 = maps:put(mon_power, MonPower, Map1),
    Map3 = maps:put(dun_id, DunId, Map2),
    Map4 = maps:put(mon_attr, DummyAttr, Map3),
    ReSupportInfo = {Module, SubModule, AutoId, TeamId, TeamLeaderName, Map4},
    lib_player:apply_cast(
        OtherRoleId, ?APPLY_CAST_SAVE, lib_guild_support_mod, after_ask_for_support, [ReSupportInfo, GameInfo]).


%% 副本挑战成功处理跑环协助任务
handle_dungeon_result(State) ->
    #dungeon_state{result_type = ResultType, role_list = [RoleDungeon | _], typical_data = TypicalData} = State,
    #dungeon_role{id = RoleId} = RoleDungeon,
    SupportId = maps:get(res_sid, TypicalData),
    GuildId = maps:get(guild_id, TypicalData),
    if
        ResultType == ?DUN_RESULT_TYPE_SUCCESS ->
            guild_run_assist:fin_run_assist(RoleId, GuildId, SupportId, ?GUILD_RUN_ASSIST_BOSS, 0);
        true ->
            guild_run_assist:fin_run_assist(RoleId, GuildId, SupportId, ?GUILD_RUN_ASSIST_BOSS, 1)
    end,
    State.

%% 任务结束
notice_task_result(Player) ->
    #player_status{role_guild_run_assist = RoleGuildRunAssist} = Player,
    lib_dungeon:active_quit(Player),
    #role_guild_run_assist{extra_data = ExtraMap} = RoleGuildRunAssist,
    NExtraMap = maps:remove(?GUILD_RUN_ASSIST_BOSS, ExtraMap),
    NRoleGuildRunAssist = RoleGuildRunAssist#role_guild_run_assist{res_sid = 0, extra_data = NExtraMap},
    NewPlayer = Player#player_status{role_guild_run_assist = NRoleGuildRunAssist},
    {ok, NewPlayer}.

%% 进入副本后，变更协助状态
enter_dun_scene(Player, DunType) ->
    if
        DunType == ?DUNGEON_TYPE_HELP ->
            #player_status{guild = Guild} = Player,
            NewGuild = Guild#status_guild{is_in_support = 1},
            Player#player_status{guild = NewGuild};
        true ->
            Player
    end.

%% 玩家复活，恢复怪至满血量
recovery_mon_hp(State) ->
    #dungeon_state{typical_data = TypicalData} = State,
    {MonPid, MonId} = maps:get(mon_pid, TypicalData),
    mon_mgr:send(MonPid, MonId, {'change_attr', [{restore_hp}]}).

%% 创怪
dispatch_dun_event({'create_mon', Wave, _MonList}, State) ->
    #dungeon_state{
        dun_id = DunId, mon_auto_id = MonAutoId, scene_id = NowSceneId,
        index_of_wave = IndexWave, scene_pool_id = ScenePoolId, typical_data = TypicalData
    } = State,
    #base_dun_wave_cfg{mon_list = [Mon|_]} = data_dungeon_wave:get_dun_wave(DunId, Wave),
    case Mon of
        {_, MonX, MonY} -> ignore;
        {_, MonX, MonY, _, _} -> ignore;
        _ -> MonX = 0, MonY = 0
    end,
    MonId = maps:get(mon_id, TypicalData),
    BaseAttr = maps:get(mon_attr, TypicalData),
    case data_mon:get(MonId) of
        #mon{type = MonType} ->
            MonType;
        _ ->
            MonType = 1
    end,
    MonKey = {?DUN_WAVE_MON_KEY, MonAutoId, Wave, IndexWave},
    MonAttrs = [{create_key, MonKey}, {type, MonType}, {attr_list, BaseAttr}, {born_handler, {?MODULE, mon_born_callback, [self()]}}],
    lib_mon:async_create_mon(MonId, NowSceneId, ScenePoolId, MonX, MonY, MonType, self(), 1, MonAttrs),
    State#dungeon_state{mon_auto_id = MonAutoId + 1};

dispatch_dun_event(Msg, State) ->
    dungeon_default:dispatch_dun_event(Msg, State).

%% 通过怪物属性计算战力
calc_mon_power(Attr) ->
    AttrList = attr_conv:to_attr_tuple_list(Attr),
    AttrRatioList = data_guild_run_assist:get_attr_ratio_by_power(),
    F = fun({AttrId, Ratio}, DummyList) ->
        case lists:keyfind(AttrId, 1, AttrList) of
            {_, Value} ->
                [{AttrId, util:ceil(Ratio * Value)} | DummyList];
            _ ->
                [{AttrId, 0} | DummyList]
        end
        end,
    DummyAttrList = lists:foldl(F, [], AttrRatioList),
    DummyAttr = attr_conv:to_attr_record(DummyAttrList),
    Power = lib_player_attr:calc_attr_power(DummyAttr),
    {Power, DummyAttrList}.

role_handle_assist_event(Player, role_trigger_cancel_assist, _Data) ->
    NewPlayer = fin_run_assist(Player),
    NewPlayer;
role_handle_assist_event(Player, _Event, _Data) ->
    Player.

%% 协助者接取协助任务
mgr_handle_assist_event({after_take_run_assist, [RoleId, GuildId, Sid]}, State) ->
    case ets:lookup(?ETS_GUILD_RUN_ASSIST, GuildId) of
        [#guild_run_assist_data{data = Date}] ->
            case maps:get(Sid, Date, 0) of
                #assist_instance{extra_data = ExtraData} ->
                    MonId = maps:get(mon_id, ExtraData),
                    MonPower = maps:get(mon_power, ExtraData),
                    BaseAttr = maps:get(mon_attr, ExtraData),
                    lib_player:apply_cast(RoleId, ?APPLY_CAST_SAVE, ?MODULE, handle_assist_event, [Sid, MonId, MonPower, BaseAttr]);
                _ ->
                    ingore
            end;
        _ ->
            ingore
    end,
    State;
%% 协助者完成任务
mgr_handle_assist_event({after_fin_run_assist, [RoleId, _GuildId, _Sid, _FinType]}, State) ->
    lib_player:apply_cast(RoleId, ?APPLY_CAST_SAVE, ?MODULE, fin_run_assist, []),
    State;
mgr_handle_assist_event(_Msg, State) ->
    State.

handle_assist_event(Player, SupportId, MonId, MonPower, BaseAttr) ->
    #player_status{role_guild_run_assist = RoleGuildRunAssist} = Player,
    #role_guild_run_assist{extra_data = ExtraMap} = RoleGuildRunAssist,
    NExtraMap = maps:put(?GUILD_RUN_ASSIST_BOSS, [MonId, MonPower, BaseAttr], ExtraMap),
    NRoleGuildRunAssist = RoleGuildRunAssist#role_guild_run_assist{res_sid = SupportId, extra_data = NExtraMap},
    NewPlayer = Player#player_status{role_guild_run_assist = NRoleGuildRunAssist},
    NewPlayer.

%% 结束boss击杀协助任务
fin_run_assist(Player) ->
    #player_status{guild = Guild, role_guild_run_assist = RoleGuildRunAssist} = Player,
    #role_guild_run_assist{extra_data = ExtraMap} = RoleGuildRunAssist,
    NExtraMap = maps:remove(?GUILD_RUN_ASSIST_BOSS, ExtraMap),
    NRoleGuildRunAssist = RoleGuildRunAssist#role_guild_run_assist{res_sid = 0, extra_data = NExtraMap},
    NewGuild = Guild#status_guild{is_in_support = 0},
    NewPlayer = Player#player_status{role_guild_run_assist = NRoleGuildRunAssist, guild = NewGuild},
    NewPlayer.