%%-----------------------------------------------------------------------------
%% @Module  :       lib_dungeon_sweep.erl
%% @Author  :       J
%% @Email   :       j-som@foxmail.com
%% @Created :       2017-10-13
%% @Description:    副本扫荡
%%-----------------------------------------------------------------------------

-module (lib_dungeon_sweep).
-include ("errcode.hrl").
-include ("def_module.hrl").
-include ("dungeon.hrl").
-include ("server.hrl").
-include ("figure.hrl").
-include ("common.hrl").
-include ("rec_event.hrl").
-include ("def_vip.hrl").
-include("def_goods.hrl").
-include("vip.hrl").
-include("def_fun.hrl").

-export ([
     check_sweep/4
    ,calc_sweep_rewards_common/4
    ,check_sweep_count/5
    ,sweep_dungeon_trigger/3

    ,sweep_show_calc/2
    ,batch_sweep/3
    % ,buy_sweep/3
    % ,buy_sweep_common/2
    ]).

%% 计算单次扫荡成本
%% 贵族特权下VIP购买次数首次免费
calc_sweep_cost(BuyCountCon, RoleId, IsSupVip, AutoNum, CostType, DunType, DunId) ->
    if CostType == 0 -> %% 免费扫荡
            [];
        true ->
            if DunType == ?DUNGEON_TYPE_MATERIAL ->
                    VipBuyCount = lib_daily:get_count(RoleId, ?MOD_DUNGEON, ?MOD_DUNGEON_BUY, DunId),
                    VipGoldBuy  = lib_daily:get_count(RoleId, ?MOD_DUNGEON, ?MOD_DUNGEON_GOLD_BUY, DunId),
                    if
                        VipBuyCount =< VipGoldBuy -> %% 红钻次数未消耗,优先消耗红钻
                            BuyingCount0 = calc_cost_count_type(DunId, AutoNum, VipBuyCount, VipGoldBuy),
                            BuyingCount  =
                            if IsSupVip -> lists:delete(1, BuyingCount0);
                                true    -> BuyingCount0
                            end;
                        true -> %% 总购买次数大于彩钻购买次数,证明红钻次数已消耗,此时消耗的都是彩钻次数
                            BuyingCount = lists:seq(VipBuyCount+1, VipBuyCount+AutoNum)
                    end;
                true ->
                    VipBuyCount  = lib_daily:get_count(RoleId, ?MOD_DUNGEON, ?MOD_DUNGEON_BUY, DunId),
                    BuyingCount0 = lists:seq(VipBuyCount+1, VipBuyCount+AutoNum),
                    BuyingCount  =
                    if IsSupVip ->
                            lists:delete(1, BuyingCount0);
                        true ->
                            BuyingCount0
                    end
            end,
            lists:foldl(fun(Count, Acc) ->
                case lists:keyfind(Count, 1, BuyCountCon) of
                    {_, _, Cost} -> lists:append([Cost], Acc);
                    _ -> Acc
                end
             end, [], BuyingCount)
    end.

%% 计算付费批量扫荡消耗
calc_batch_sweep_cost(BuyCountCon, _RoleId, VipGoldBuy, NewCount) ->
    BuyingCount = lists:seq(VipGoldBuy+1, VipGoldBuy+NewCount),
    lists:foldl(fun(Count, Acc) ->
        case lists:keyfind(Count, 1, BuyCountCon) of
            {_, _, {GoodsType, GoodsId, Num}} ->
                [{GoodsType, GoodsId, Num}|Acc];
            _ -> Acc
        end
    end, [], BuyingCount).

%% 判断本次消耗的是红钻次数还是彩钻次数
calc_cost_count_type(DunId, AutoNum, VipBuyCount, VipGoldBuy) ->
    #dun_cfg{buy_count_cost = BuyCost} = data_dungeon:get_dun(DunId),
    MaxBgoldCount = calc_bgold_count(BuyCost, 0),
    VipBgoldBuy = VipBuyCount - VipGoldBuy,
    if
        VipBgoldBuy >= MaxBgoldCount -> %% 红钻次数已消耗完
            lists:seq(VipBuyCount+1, VipBuyCount+AutoNum);
        true -> %% 红钻剩余次数
            BgoldCanBuy = min(MaxBgoldCount, VipBgoldBuy+AutoNum),
            lists:seq(VipBgoldBuy+1, VipBgoldBuy+BgoldCanBuy)
    end.

calc_bgold_count([], MaxBgoldCount) ->
    MaxBgoldCount;
calc_bgold_count([{Count, _Vip, {GoodsType, _GoodsId, _GoodsNum}}|Rest], TmpMaxBgoldCount) ->
    if GoodsType == ?TYPE_BGOLD ->
            if Count > TmpMaxBgoldCount ->
                    calc_bgold_count(Rest, Count);
                true ->
                    calc_bgold_count(Rest, TmpMaxBgoldCount)
            end;
        true ->
            calc_bgold_count(Rest, TmpMaxBgoldCount)
    end.

calc_sweep_rewards(Player, #dun_cfg{type = _DunType} = Dun, AutoNum, Mul, CostType) ->
    lib_dungeon_distribute:calc_sweep_rewards(Player, Dun, AutoNum, Mul, CostType).

%% 单次扫荡默认操作
calc_sweep_rewards_common(DunCfg, AutoNum, Mul, CostType) ->
    #dun_cfg{base_reward = Rewards0, rand_reward = RandReward0} = DunCfg,
    Rewards = dungeon_default:calc_reward_with_rand(Rewards0),
    Rewards1 = dungeon_default:calc_reward_with_rand(RandReward0),
    AllRewards = lists:append([Rewards, Rewards1]),
    %% vip付费扫荡一倍+活动buff倍数 总倍数
    NewMul =
    if CostType == 1 -> Mul+1;
        true -> Mul
    end,
    RewardsAfterMul = case lib_goods_util:is_random_goods_rewards(AllRewards) of
        false ->
            MulRewards = sweep_goods_multiple(AllRewards, NewMul),
            lists:append([MulRewards || _ <- lists:seq(1, AutoNum)]);
        _ ->
            Rs = lib_goods_util:calc_random_goods_rewards(AllRewards),
            MulRewards = sweep_goods_multiple(Rs, NewMul),
            lists:append([MulRewards || _ <- lists:seq(1, AutoNum)])
    end,
    {ok, RewardsAfterMul}.

check_sweep(Player, DunId, AutoNum, CostType) ->
    DunType = data_dungeon:get_dun_type(DunId),
    #player_status{id = RoleId, vip_status = VipStatus,
     dungeon = #status_dungeon{flop = #role_dun_flop{tmp_flop = TmpFlop}},
     dungeon_record = DungeonRecs} = Player,
    IsSupVip = lib_sup_vip:is_sup_vip(VipStatus),
    case DungeonRecs of
        undefined -> DunRec = [];
        _ -> DunRec = maps:get(DunId, DungeonRecs, [])
    end,
    CheckList = [
        {dun_check, DunId},
        {sweep_num_check, AutoNum},
        {pass_before_sweep, RoleId, DunType, DunId, VipStatus, DunRec},
        {dun_flop_check, TmpFlop}
    ],
    case sweep_common_check(CheckList) of
        true ->
            %% 次数是否已用完
            #dun_cfg{buy_count_cost = BuyCountCon} = Dun = data_dungeon:get_dun(DunId),
            DailyList = lists:append([
                lib_dungeon_api:get_daily_count_type_list(DunType),
                lib_dungeon_api:get_daily_buy_type_list(DunType),
                lib_dungeon_api:get_vip_use_type_list(DunType)
            ]),
            DailyCountList = lib_daily:get_count(Player#player_status.id, DailyList),
            Result = lib_dungeon_distribute:check_sweep_daily_count(Player, Dun, AutoNum, CostType, DailyCountList),
            case Result of
                true ->
                    Mul = lib_dungeon:get_mul_drop_times(Dun, Player),
                    UniteBuffNum =
                    if DunType == ?DUNGEON_TYPE_MATERIAL ->
                        case custom_unite_buff:check_buff(Player, dungeon_double) of
                            {ok, Num} -> max(0, round(Num/100)-1);
                            _         -> 0
                        end;
                        true -> 0
                    end,
                    %% 基础倍数+副本定制活动多倍+材料本多倍
                    NewNul = 1+max(0, Mul-1)+UniteBuffNum,
                    % ?ERR("~p ~p ~p ~p", [CostType, UniteBuffNum, Mul, NewNul]),
                    case calc_sweep_rewards(Player, Dun, AutoNum, NewNul, CostType) of
                        {ok, RewardsList} -> %?ERR("~p", [RewardsList]),
                            AllSweepCost = calc_sweep_cost(BuyCountCon, RoleId, IsSupVip, AutoNum, CostType, DunType, DunId),
                            case lib_goods_api:check_object_list(Player, AllSweepCost) of
                                true ->
                                    {ok, RewardsList, AllSweepCost};
                                {false, ErrorCode} ->
                                    {false, ErrorCode};
                                _ ->
                                    {false, ?ERRCODE(goods_not_enough)}
                            end;
                        Error ->
                            Error
                    end;
                false ->
                    {false, ?ERRCODE(err610_dungeon_count_daily_sweep)};
                {false, ErrorCode} ->
                    {false, ErrorCode};
                _ ->
                    {false, ?FAIL}
            end;
        {false, Error} ->
            {false, Error}
    end.

check_sweep_count(Player, Dun, Num, CostType, DailyList) ->
    #player_status{id = RoleId, figure = #figure{vip = VipLv}} = Player,
    #dun_cfg{id = DunId, type = DunType, count_cond = CountCondition, buy_count_cost = BuyCountCon} = Dun,
    UniteBuffNum = custom_unite_buff:get_unite_num(Player, DunType),
    % UniteBuffNum = 1,
    do_check_sweep_count(RoleId, VipLv, DunType, DunId, Num, CostType, DailyList, CountCondition, BuyCountCon, UniteBuffNum).

do_check_sweep_count(RoleId, VipLv, DunType, DunId, AutoNum, CostType, DailyList, [{?DUN_COUNT_COND_DAILY, Max}|T], BuyCountCon, UniteBuffNum) ->
    if CostType == 0 -> %% 免费扫荡(免费次数的扫荡)
            CountType = lib_dungeon_api:get_daily_count_type(DunType, DunId),
            UseCount =
             case lists:keyfind({?MOD_DUNGEON, ?MOD_DUNGEON_ENTER, CountType}, 1, DailyList) of
                {_, Count} -> Count;
                _          -> 0
            end,
            NMax = Max+UniteBuffNum,
            if
                UseCount + AutoNum =< NMax ->
                    do_check_sweep_count(RoleId, VipLv, DunType, DunId, AutoNum, CostType, DailyList, T, BuyCountCon, UniteBuffNum);
                true ->
                    {false, ?ERRCODE(err610_dungeon_count_daily_sweep)}
            end;
        true -> %% 付费扫荡(vip购买次数的扫荡)
            case calc_vip_max_can_buy(VipLv, BuyCountCon) of
                {ConfigVipBuySweepCount, _, _Cost} ->
                    case lists:keyfind({?MOD_DUNGEON, ?MOD_DUNGEON_BUY, DunId}, 1, DailyList) of
                        {_, RoleVipBuyCount} ->
                            if RoleVipBuyCount + AutoNum > ConfigVipBuySweepCount->
                                    {false, ?ERRCODE(err610_buy_limit_error)};
                                true ->
                                    do_check_sweep_count(RoleId, VipLv, DunType, DunId, AutoNum, CostType, DailyList, T, BuyCountCon, UniteBuffNum)
                            end;
                        _ ->
                            {false, ?ERRCODE(err610_vip_buy_count_limit)}
                    end;
                _ ->
                    {false, ?ERRCODE(err610_buy_limit_error)}
            end
    end;

do_check_sweep_count(RoleId, VipLv, DunType, DunId, AutoNum, CostType, DailyList, [{?DUN_COUNT_COND_WEEK, Max}|T], BuyCountCon, UniteBuffNum) ->
    Num = lib_week:get_count(RoleId, ?MOD_DUNGEON, ?MOD_DUNGEON_ENTER, DunId),
    if
        Num + AutoNum =< Max ->
            do_check_sweep_count(RoleId, VipLv, DunType, DunId, AutoNum, CostType, DailyList, T, BuyCountCon, UniteBuffNum);
        true ->
            {false, ?ERRCODE(err610_dungeon_count_weekly_sweep)}
    end;

do_check_sweep_count(RoleId, VipLv, DunType, DunId, AutoNum, CostType, DailyList, [{?DUN_COUNT_COND_PERMANENT, Max}|T], BuyCountCon, UniteBuffNum) ->
    Num = lib_counter:get_count(RoleId, ?MOD_DUNGEON, ?MOD_DUNGEON_ENTER, DunId),
    if
        Num + AutoNum =< Max ->
            do_check_sweep_count(RoleId, VipLv, DunType, DunId, AutoNum, CostType, DailyList, T, BuyCountCon, UniteBuffNum);
        true ->
            {false, ?ERRCODE(err610_dungeon_count_permanent_sweep)}
    end;

do_check_sweep_count(RoleId, VipLv, DunType, DunId, AutoNum, CostType, DailyList, [_|T], BuyCountCon, UniteBuffNum) ->
    do_check_sweep_count(RoleId, VipLv, DunType, DunId, AutoNum, CostType, DailyList, T, BuyCountCon, UniteBuffNum);

do_check_sweep_count(_RoleId, _VipLv, _DunType, _DunId, _AutoNum, _, _VipBuyCount, [], _BuyCountCon, _UniteBuffNum) ->
    true.

calc_vip_max_can_buy(VipLv, BuyCountCon) ->
    if BuyCountCon == [] ->
            {0, 0, []};
        true ->
            ChoseMaxCount = lists:foldl(fun({ConfigCount, ConfigVip, _}, TmpMaxCount) ->
                if VipLv < ConfigVip -> TmpMaxCount;
                    true ->
                        max(ConfigCount, TmpMaxCount)
                end
             end, 0, BuyCountCon),
            if  ChoseMaxCount =/= 0 ->
                    case lists:keyfind(ChoseMaxCount, 1, BuyCountCon) of
                        ChoseVipCount = {_, _, _} ->
                            ChoseVipCount;
                        _ ->
                            {0, 0, []}
                    end;
                true ->
                    {0, 0, []}
            end
    end.

%% 材料副本批量扫荡展示-永久贵族特权
%% 0普通扫荡(免费+第一次购买次数的扫荡)|1(彩钻购买次数的扫荡)
sweep_show_calc(DunType, #player_status{id = RoleId, sid = Sid} = Player) ->
    #player_status{id = RoleId, vip_status = VipStatus, dungeon = StatusDungeon, dungeon_record = DungeonRecs, figure = #figure{vip = VipLv, lv = RoleLv}} = Player,
    case show_sweep_check(RoleId, DunType, DungeonRecs) of
        {true, DunIds} -> %% 可供扫荡的副本id
            if DunIds =/= [] ->
                    #status_dungeon{sweep_reward_calc = RewardCalc} = StatusDungeon,
                    DoubleBuff =
                    case custom_unite_buff:check_buff(Player, dungeon_double) of
                        {ok, Num} -> max(0, round(Num/100)-1);
                        _         -> 0
                    end,
                    UniteBuffNum = custom_unite_buff:get_unite_num(Player, DunType),
                    % ?ERR("batch sweep calc ~p ~p ~p", [DunIds, DoubleBuff, UniteBuffNum]),
                    IsSupVip = lib_sup_vip:is_sup_vip(VipStatus),
                    FreeSweep = calc_free_sweep(RoleId, DunType, VipLv, IsSupVip, DunIds, RoleLv, DoubleBuff, UniteBuffNum),
                    CostSweep = calc_cost_sweep(RoleId, DunType, VipLv, IsSupVip, DunIds, RoleLv, DoubleBuff),
                    NewRewardCalc    = update_reward_calc(?BATCH_FREE_SWEEP, FreeSweep, RewardCalc),
                    NewRewardCalc1   = update_reward_calc(?BATCH_COST_SWEEP, CostSweep, NewRewardCalc),
                    NewStatusDungeon = StatusDungeon#status_dungeon{sweep_reward_calc = NewRewardCalc1},
                    AllSweep  = calc_all_sweep(FreeSweep, CostSweep),
                    % ?ERR("~p ~n ~p", [FreeSweep, CostSweep]),
                    lib_server_send:send_to_sid(Sid, pt_610, 61066, [?SUCCESS, DunType, AllSweep]),
                    {ok, Player#player_status{dungeon = NewStatusDungeon}};
                true ->
                    lib_server_send:send_to_sid(Sid, pt_610, 61066, [?ERRCODE(err610_today_not_pass), DunType, []])
            end;
        {false, Error} ->
            lib_server_send:send_to_sid(Sid, pt_610, 61066, [Error, DunType, []]),
            ok
    end.

update_reward_calc(MapType, SweepList, RewardCalc) ->
    maps:put(MapType, SweepList, RewardCalc).

%% 材料副本批量扫荡
batch_sweep(Player, DunType, Type) ->
    #player_status{id = RoleId, sid = Sid, dungeon_record = DungeonRecs} = Player,
    case show_sweep_check(RoleId, DunType, DungeonRecs) of
        {true, DunIds} ->
            case batch_sweep_do(Type, Player, DunType, DunIds) of
                {ok, NewPlayer, _DunCountList} ->
                    {ok, NewPlayer};
                _A ->
                    ok
            end;
        {false, Error} ->
            lib_server_send:send_to_sid(Sid, pt_610, 61028, [Error, Type, DunType]),
            ok
    end.

%% 免费扫荡
batch_sweep_do(Type = 0, Player, DunType, _DunIds) ->
    #player_status{id = RoleId, sid = Sid, dungeon = StatusDungeon} = Player,
    #status_dungeon{sweep_reward_calc = SweepReward} = StatusDungeon,
    case maps:get(?BATCH_FREE_SWEEP, SweepReward, []) of
        [{_, Rewards, CostFreeCountList, SupVipFreeCounts, Cost, CustomReward}|_] ->
            if Rewards == [] ->
                    lib_server_send:send_to_sid(Sid, pt_610, 61028, [?ERRCODE(err610_dun_have_all_sweeped), Type, DunType]),
                    ok;
                true ->
                    Ret =
                    if Cost > 0 ->
                            case lib_goods_api:cost_object_list_with_check(Player, [{?TYPE_BGOLD, 0, Cost}], dun_batch_sweep_cost, integer_to_list(Type)) of
                                {true, NewPlayer, _} ->
                                    {?SUCCESS, NewPlayer};
                                {false, Error, _} ->
                                    {Error, Player}
                            end;
                        true ->
                            {?SUCCESS, Player}
                    end,
                    case Ret of
                        {1, Player1} ->
                            Player2  = lib_goods_api:send_reward(Player1, Rewards++CustomReward, dun_batch_sweep),
                            free_sweep_count_update(RoleId, CostFreeCountList),
                            cost_sweep_count_update(RoleId, ?TYPE_BGOLD, SupVipFreeCounts),
                            AllFreeCounts = lists:append([CostFreeCountList, SupVipFreeCounts]),
                            DunCountList  = calc_dun_all_count(CostFreeCountList, SupVipFreeCounts),
                            DunIds1    = calc_trigger_duns(AllFreeCounts),
                            NewPlayer1 = sweep_dungeon_trigger(Player2, DunType, DunIds1),
                            NewSweepReward = maps:remove(?BATCH_FREE_SWEEP, SweepReward),
                            NewPlayer2 = NewPlayer1#player_status{dungeon = StatusDungeon#status_dungeon{sweep_reward_calc = NewSweepReward}},
                            lib_server_send:send_to_sid(Sid, pt_610, 61028, [?SUCCESS, Type, DunType]),
                            {ok, NewPlayer2, DunCountList};
                        {Error1, _} ->
                            lib_server_send:send_to_sid(Sid, pt_610, 61028, [Error1, Type, DunType]),
                            ok
                    end
            end;
        _ ->
            lib_server_send:send_to_sid(Sid, pt_610, 61028, [?ERRCODE(err610_sweep_data_error), Type, DunType]),
            ok
    end;
%% 付费扫荡
batch_sweep_do(Type = 1, Player, DunType, _DunIds) ->
    #player_status{
        id = RoleId, sid = Sid,
        dungeon = StatusDungeon = #status_dungeon{sweep_reward_calc = SweepReward}
    } = Player,
    DefaultData1 = [{0, [], [], 0, []}],
    [{_, Rewards, CostCountList, MoneyCost, CustomRewards}|_] = maps:get(?BATCH_COST_SWEEP, SweepReward, DefaultData1),
    AllRewards = merge_object_list(lists:append([Rewards, CustomRewards]), []),
    ObjectList = [{?TYPE_GOLD, 0, MoneyCost}],
    if Rewards =/= [] ->
            Result =
            if MoneyCost > 0 ->
                    case lib_goods_api:cost_object_list_with_check(Player, ObjectList, dun_batch_sweep_cost, integer_to_list(Type)) of
                        {true, NewPlayer, _} ->
                            {?SUCCESS, NewPlayer};
                        {false, Error, _} ->
                            {Error, Player}
                    end;
                true ->
                    {?SUCCESS, Player}
            end,
            case Result of
                {1, NewPlayer0} ->
                    NewPlayer1 = lib_goods_api:send_reward(NewPlayer0, AllRewards, dun_cost_batch_sweep_reward),
                    cost_sweep_count_update(RoleId, ?TYPE_GOLD, CostCountList),
                    DunIds1    = calc_trigger_duns(CostCountList),
                    NewPlayer2 = sweep_dungeon_trigger(NewPlayer1, DunType, DunIds1),
                    NewSweepReward  = maps:remove(?BATCH_COST_SWEEP, SweepReward),
                    % ?ERR("~p", [NewSweepReward1]),
                    NewStatusDungeon = StatusDungeon#status_dungeon{sweep_reward_calc = NewSweepReward},
                    NewPlayer3 = NewPlayer2#player_status{dungeon = NewStatusDungeon},
                    lib_server_send:send_to_sid(Sid, pt_610, 61028, [?SUCCESS, Type, DunType]),
                    {ok, NewPlayer3, CostCountList};
                {Error1, _} ->
                    lib_server_send:send_to_sid(Sid, pt_610, 61028, [Error1, Type, DunType]),
                    ok
            end;
        true ->
            lib_server_send:send_to_sid(Sid, pt_610, 61028, [?ERRCODE(err610_dun_have_all_sweeped), Type, DunType]),
            ok
    end.

calc_dun_all_count(FreeCountList, CostCountList) ->
    lists:foldl(fun({DunId, Count}, TmpCostCountList) ->
        case lists:keyfind(DunId, 1, TmpCostCountList) of
            {_, OldCount} ->
                lists:keystore(DunId, 1, TmpCostCountList, {DunId, OldCount+Count});
            _ ->
                lists:keystore(DunId, 1, TmpCostCountList, {DunId, Count})
        end
     end, CostCountList, FreeCountList).

free_sweep_count_update(RoleId, List) ->
    [begin
        #dun_cfg{type = DunType, count_cond = CountCondition} = data_dungeon:get_dun(DunId),
        lib_dungeon:dungeon_count_plus(CountCondition, DunId, DunType, RoleId, CostCount),
        lib_counter:plus_count(RoleId, ?MOD_DUNGEON, ?MOD_DUNGEON_SUCCESS, DunId, CostCount),
        lib_daily:plus_count(RoleId, ?MOD_DUNGEON, ?MOD_DUNGEON_SUCCESS, DunId, CostCount)
     end|| {DunId, CostCount} <- List].

cost_sweep_count_update(RoleId, GoodsType, List) ->
    [begin
        #dun_cfg{type = DunType, count_cond = CountCondition} = data_dungeon:get_dun(DunId),
        lib_dungeon:dungeon_buy_count_plus(CountCondition, GoodsType, DunId, DunType, RoleId, CostCount)
    end || {DunId, CostCount} <- List].

calc_trigger_duns(CountList) ->
    lists:foldl(fun({DunId, Count}, Acc) ->
        DunIds = lists:duplicate(Count, DunId),
        lists:append(DunIds, Acc)
     end, [], CountList).

calc_free_sweep(RoleId, DunType, VipLv, IsSupVip, DunIds, RoleLv, DoubleBuffNum, UniteBuffNum) ->
    {FinalRewards, FinalCount, SupFreeCount, FinalCost, FinalCustomRewards} = lists:foldl(fun(DunId, {TmpRewards, TmpCountList, TmpSupVipFreeCounts, TmpMoneyCost, TmpCustomRewards}) ->
            CountType = lib_dungeon_api:get_daily_pass_type(DunType, DunId),
            EnterCount = lib_daily:get_count(RoleId, ?MOD_DUNGEON, ?MOD_DUNGEON_ENTER, CountType),
            #dun_cfg{base_reward = BaseReward0, rand_reward = RandReward0, count_cond = CountCondition, buy_count_cost = BuyCountCon} = data_dungeon:get_dun(DunId),
            case lists:keyfind(?DUN_COUNT_COND_DAILY, 1, CountCondition) of
                {_, MaxCount} -> ok; _ -> MaxCount = 0
            end,
            NewMaxCount = MaxCount + UniteBuffNum,
             if EnterCount >= NewMaxCount -> FreeCount = 0;
                true -> FreeCount = NewMaxCount - EnterCount
            end,
            VipFirstCount = calc_vip_buy_first_count(RoleId, DunId, VipLv, IsSupVip, BuyCountCon),
            %% 正常次数+购买次数的首次+额外材料提交buff次数属于批量免费扫荡
            TotalCount = FreeCount + VipFirstCount,
            % ?ERR("~p ~p ~p", [VipLv, FreeCount, VipFirstCount]),
            if TotalCount =/= 0 ->
                    BaseReward = dungeon_default:calc_reward_with_rand(BaseReward0),
                    %% 定制活动副本奖励多倍|1即无多倍
                    MultiTimes = lib_dungeon_api:get_custom_act_reward_times(DunType, DunId, RoleLv),
                    %% 基础倍数 + 材料buff倍数 + 定制活动奖励倍数
                    Mul = 1 + DoubleBuffNum + max(MultiTimes - 1, 0),
                    % _FreeWithBuffCount = FreeCount + UniteBuffNum,
                    if FreeCount > 0 ->
                            %% 基础奖励*次数
                            DunRewards0 = sweep_goods_multiple(BaseReward, FreeCount),
                            %% 总次数奖励*倍数
                            ReAfterBuff = sweep_goods_multiple(DunRewards0, Mul),
                            %% 单次随机奖励*倍数的总和
                            DunRandRewards0 = sweep_goods_rand(RandReward0, FreeCount, Mul),
                            DunRewards1 = ReAfterBuff ++ DunRandRewards0;
                        true ->
                            DunRewards1 = []
                    end,
                    if  VipFirstCount > 0 ->
                            %% 付费扫荡多一倍
                            VipMul = Mul + 1,
                            %% 基础奖励*付费次数
                            DunRewards2  = sweep_goods_multiple(BaseReward, VipFirstCount),
                            %% 总次数奖励*倍数
                            ReAfterBuff1 = sweep_goods_multiple(DunRewards2, VipMul),
                            %% 单次随机奖励*付费倍数的总和
                            DunRandRewards2 = sweep_goods_rand(RandReward0, VipFirstCount, VipMul),
                            DunRewards3  = ReAfterBuff1 ++ DunRandRewards2,
                            if not IsSupVip ->
                                    Cost = lib_dungeon:calc_buy_count_cost(BuyCountCon, 0, 1, VipLv),
                                    TmpMoneyCost1 = TmpMoneyCost + lists:sum([NumX|| {_, _, NumX} <- Cost]);
                                true ->
                                    TmpMoneyCost1 = TmpMoneyCost
                            end;
                        true ->
                            DunRewards3 = [],
                            TmpMoneyCost1 = TmpMoneyCost
                    end,
                    LastDunRewards = DunRewards1 ++ DunRewards3,
                    CustomReward  = [],
                    NewTmpRewards = lists:append([LastDunRewards, TmpRewards]),
                    NewCountList  = [{DunId, FreeCount}|TmpCountList],
                    NewSupVipFreeCounts = [{DunId, VipFirstCount}|TmpSupVipFreeCounts],
                    NewCustomReward = TmpCustomRewards ++ CustomReward,
                    {NewTmpRewards, NewCountList, NewSupVipFreeCounts, TmpMoneyCost1, NewCustomReward};
                true ->
                    {TmpRewards, TmpCountList, TmpSupVipFreeCounts, TmpMoneyCost, TmpCustomRewards}
            end
     end, {[], [], [], 0, []}, DunIds),
    [{0, FinalRewards, FinalCount, SupFreeCount, FinalCost, FinalCustomRewards}].

%% 计算是否还有红钻扫荡次数
%% 红钻扫荡算批量免费扫荡一种
calc_vip_buy_first_count(RoleId, DunId, VipLv, _IsSupVip, BuyCountCon) ->
    case calc_vip_max_can_buy(VipLv, BuyCountCon) of
        {ConfigVipBuySweepCount, _, _Cost} ->
            VipBuyCount = lib_daily:get_count(RoleId, ?MOD_DUNGEON, ?MOD_DUNGEON_BUY, DunId),
            VipGoldBuy  = lib_daily:get_count(RoleId, ?MOD_DUNGEON, ?MOD_DUNGEON_GOLD_BUY, DunId),
            if ConfigVipBuySweepCount =< VipBuyCount ->
                    0;
                true ->
                    if  VipBuyCount =< VipGoldBuy ->
                            1;
                        true ->
                            0
                    end
            end;
        _ ->
            0
    end.

calc_cost_sweep(RoleId, DunType, VipLv, _IsSupVip, DunIds, RoleLv, DoubleBuffNum) ->
    {FinalRewards, FinalCount, FinalCost, FinalCustomRewards} = lists:foldl(fun(DunId, {TmpRewards, CountList, MoneyCost, TmpCustomRewards}) ->
        #dun_cfg{type = DunType, base_reward = BaseReward0, rand_reward = RandReward0, buy_count_cost = BuyCountCon} = data_dungeon:get_dun(DunId),
        case calc_vip_max_can_buy(VipLv, BuyCountCon) of
            {ConfigVipBuySweepCount, _, _Cost} ->
                VipBuyCount = lib_daily:get_count(RoleId, ?MOD_DUNGEON, ?MOD_DUNGEON_BUY, DunId),
                VipGoldBuy  = lib_daily:get_count(RoleId, ?MOD_DUNGEON, ?MOD_DUNGEON_GOLD_BUY, DunId),
                % ?ERR("batch sweep vip can buy ~p current buy ~p", [ConfigVipBuySweepCount, VipBuyCount]),
                if ConfigVipBuySweepCount =< VipBuyCount ->
                        {TmpRewards, CountList, MoneyCost, TmpCustomRewards};
                    true ->
                        if VipGoldBuy >= VipBuyCount -> %% 还有红钻次数
                                NewCount = ConfigVipBuySweepCount - (VipGoldBuy + 1);
                            true ->
                                NewCount = ConfigVipBuySweepCount - VipBuyCount
                        end,
                        BaseReward = dungeon_default:calc_reward_with_rand(BaseReward0),
                        %% 定制活动副本奖励多倍 1即无倍数
                        MultiTimes = lib_dungeon_api:get_custom_act_reward_times(DunType, DunId, RoleLv),
                        %% 基础倍数+VIP倍数+材料提交倍数+定制活动奖励倍数
                        Mul = 1 + 1 + DoubleBuffNum + max(0, MultiTimes - 1),
                        %% 基础奖励*次数
                        BaseReward1 = sweep_goods_multiple(BaseReward, NewCount),
                        %% 总次数奖励*倍数
                        ReAfterBuff = sweep_goods_multiple(BaseReward1, Mul),
                        %% 单次随机奖励*倍数 之和
                        RandReward = sweep_goods_rand(RandReward0, NewCount, Mul),

                        DunRewards = lists:append([ReAfterBuff, RandReward]),

                        NewTmpRewards = lists:append(DunRewards, TmpRewards),

                        NewCountList  = [{DunId, NewCount}|CountList],
                        SweepCost     = calc_batch_sweep_cost(BuyCountCon, RoleId, VipGoldBuy+1, NewCount),
                        NewMoneyCost  = MoneyCost + lists:sum([Num || {_, _, Num} <- SweepCost]),
                        NewCustomRewards = TmpCustomRewards,
                        {NewTmpRewards, NewCountList, NewMoneyCost, NewCustomRewards}
                end;
            _ -> %?ERR("can not find avaliable count", []),
                {TmpRewards, CountList, MoneyCost, TmpCustomRewards}
        end
     end, {[], [], 0, []}, DunIds),
    [{1, FinalRewards, FinalCount, FinalCost, FinalCustomRewards}].

calc_all_sweep(FreeSweep, CostSweep) ->
    [{SweepType, Rewards, CountList, SupVipFreeCounts, MoneyCost, CustomRewards}|_] = FreeSweep,
    Count  = lists:sum([CountX || {_DunIdX, CountX} <- CountList ++ SupVipFreeCounts]),
    [{SweepType1, Rewards1, CountList1, MoneyCost1, CustomRewards1}|_] = CostSweep,
    Count1 = lists:sum([Count0 || {_DunId0, Count0} <- CountList1]),
    % AllRewards = lists:append([Rewards, Rewards1]),
    % AllCount = Count+Count1,
    lists:append([[{SweepType, Rewards, CustomRewards, Count, MoneyCost}], [{SweepType1, Rewards1, CustomRewards1, Count1, MoneyCost1}]]).

%% 09/02 经验也修改成多倍
sweep_goods_multiple(GoodsList, 1) -> GoodsList;
sweep_goods_multiple(GoodsList, X) ->
    [
        begin
            case Object of
                {?TYPE_EXP, GTypeId, Num} ->
                    {?TYPE_EXP, GTypeId, Num*X};
                {Type, GTypeId, Num} ->
                    {Type, GTypeId, trunc(Num*X)};
                {GTypeId, Num} ->
                    {GTypeId, trunc(Num*X)}
            end
        end || Object <- GoodsList
    ].

sweep_goods_rand(RandReward, Count, CountType) ->
    Rewards = sweep_goods_rand_do(RandReward, Count, CountType, []),
    lists:filter(fun({GoodsType, GoodsId, _Num}) ->
        if GoodsType == 0 andalso GoodsId == 0 -> false;
            true -> true
        end
     end, Rewards).

sweep_goods_rand_do(_, Count, _, Rewards) when Count < 1 ->
    Rewards;
sweep_goods_rand_do(RandReward, Count, CountType, Rewards) ->
    case RandReward of
        [RandNum, RandGoodsList|_] ->
            GoodsList0 = urand:list_rand_by_weight(RandGoodsList, RandNum),
            GoodsList = lists:append(GoodsList0),
            NewRewards0 = sweep_goods_multiple(GoodsList, CountType),
            NewRewards = lists:append(NewRewards0, Rewards),
            sweep_goods_rand_do(RandReward, Count-1, CountType, NewRewards);
        _ ->
            sweep_goods_rand_do(RandReward, Count-1, CountType, Rewards)
    end.

%% 今日或历史需通过关
show_sweep_check(RoleId, DunType, DungeonRecs) ->
    case data_dungeon:get_ids_by_type(DunType) of
        DunIds = [_|_] ->
            FilterDunIds  = lists:filter(fun(DunId) ->
                case DunType of
                    ?DUNGEON_TYPE_MATERIAL ->
                        CountType = lib_dungeon_api:get_daily_pass_type(DunType, DunId),
                        IsPass = lib_counter:get_count(RoleId, ?MOD_DUNGEON, ?MOD_DUNGEON_SUCCESS, CountType),
                        DunRec = maps:get(DunId, DungeonRecs, []),
                        case lists:keyfind(?DUNGEON_REC_RATING, 1, DunRec) of
                            {_, MaxRating} -> ok;
                            _ -> MaxRating = 0
                        end,
                        IsPass =/= 0 andalso MaxRating >= 5;
                    _ ->
                        CountType = lib_dungeon_api:get_daily_pass_type(DunType, DunId),
                        IsPass = lib_daily:get_count(RoleId, ?MOD_DUNGEON, ?MOD_DUNGEON_SUCCESS, CountType),
                        IsPass =/= 0
                end
             end, DunIds),
            {true, FilterDunIds};
        [] ->
        {false, ?ERRCODE(err432_not_sweep_times)};
        _ ->
            {false, ?ERRCODE(err610_dun_type_error)}
    end.


merge_object_list([{Type, Id, Num}|T], All) ->
    case lists:keyfind({Type, Id}, 1, All) of
        {_, Num0} ->
            All1 = lists:keystore({Type, Id}, 1, All, {{Type, Id}, Num0 + Num});
        _ ->
            All1 = [{{Type, Id}, Num} | All]
    end,
    merge_object_list(T, All1);

merge_object_list([{Id, Num}|T], All) ->
    case lists:keyfind({?TYPE_GOODS, Id}, 1, All) of
        {_, Num0} ->
            All1 = lists:keystore({?TYPE_GOODS, Id}, 1, All, {{?TYPE_GOODS, Id}, Num0 + Num});
        _ ->
            All1 = [{{?TYPE_GOODS, Id}, Num} | All]
    end,
    merge_object_list(T, All1);

merge_object_list([], All) ->
    [{Type, Id, Num} || {{Type, Id}, Num} <- All].

%% 扫荡触发
sweep_dungeon_trigger(Player, DunType, DunIds) ->
    HiPointIsEnterTrigger = lists:member(DunType, ?HI_POINT_DUNGEON_SCORE_TRIGGER),
    F = fun(DunId, TPlayer) ->
        #player_status{id = RoleId} = TPlayer,
        Player2 = lib_child_task:finish_dungeon(TPlayer, DunType, DunId, 1),
        Player3 = handle_achievement(Player2, [DunId]),
        lib_dungeon:handle_task_trigger(Player3, #callback_dungeon_succ{dun_type=DunType, dun_id = DunId, distribute = ?DUN_TASK_PASS_TRIGGER}),
        lib_activitycalen_api:finish_dungeon(RoleId, ?MOD_DUNGEON, DunType, DunId),
        contract_task_api:dun_task_trigger(RoleId, DunId, DunType, 1),
        if
            HiPointIsEnterTrigger ->
                mod_hi_point:success_end(RoleId, ?MOD_DUNGEON, DunType),
                custom_act_adventure:do_trigger_adventure_task(RoleId, ?MOD_DUNGEON, DunType);
            true ->
                skip
        end,
        lib_activitycalen_api:success_finish_dungeon(RoleId, ?MOD_DUNGEON, DunType, DunId),
        custom_act_mobilize:finish_dungeon(RoleId, DunType, DunId),
        lib_custom_act_slices:finish_dungeon(RoleId, DunType),
        {ok, Player4} = lib_seven_days_goal:finish_dungeon_task(Player3, ?MOD_DUNGEON, DunId, 1),
        DunType == ?DUNGEON_TYPE_MATERIAL andalso lib_role_legion:trigger_task(Player4, ?MOD_DUNGEON, 1),
        DunType == ?DUNGEON_TYPE_VISUS andalso lib_role_legion:trigger_task(Player4, ?MOD_DUNGEON, 7),
        Player4
    end,
    NewPlayer = lists:foldl(F, Player, DunIds),
    if DunType == ?DUNGEON_TYPE_MATERIAL ->
            DunCounts = calc_dun_sweep_count(DunIds),
            lists:map(fun({DunIdX, DunCount}) ->
                lib_dungeon_api:ta_dun_ret(NewPlayer, DunType = ?DUNGEON_TYPE_MATERIAL, [DunIdX, true, ?DUN_RESULT_TYPE_SUCCESS, DunCount])
            end, DunCounts);
        true -> skip
    end,
    NewPlayer.

calc_dun_sweep_count(DunIds) ->
    calc_dun_sweep_count_1(DunIds, []).

calc_dun_sweep_count_1([], AccCounts) ->
    AccCounts;
calc_dun_sweep_count_1([DunId|Rest], AccCounts) ->
    case lists:keyfind(DunId, 1, AccCounts) of
        {_, OldCount} ->
            calc_dun_sweep_count_1(Rest, lists:keystore(DunId, 1, AccCounts, {DunId, OldCount+1}));
        _ ->
            calc_dun_sweep_count_1(Rest, lists:keystore(DunId, 1, AccCounts, {DunId, 1}))
    end.

handle_achievement(Player, [DunId|T]) ->
    NewPlayer = lib_dungeon:handle_achievement(Player, DunId),
    handle_achievement(NewPlayer, T);

handle_achievement(Player, []) -> Player.


sweep_common_check([]) -> true;
sweep_common_check([{dun_check, DunId}|Rest]) ->
    case data_dungeon:get_dun(DunId) of
        #dun_cfg{} ->
            sweep_common_check(Rest);
        _ ->
            {false, ?ERRCODE(err_config)}
    end;
sweep_common_check([{sweep_num_check, AutoNum}|Rest]) ->
    if AutoNum =< 0 ->
            {false, ?FAIL};
        true ->
            sweep_common_check(Rest)
    end;
sweep_common_check([{pass_before_sweep, RoleId, DunType, DunId, VipStatus, DunRec}|Rest]) ->
    if
        DunType == ?DUNGEON_TYPE_EXP -> %% 经验副本扫荡
            true;
        true ->
            Res =
            if
                DunType == ?DUNGEON_TYPE_VIP -> %% vip副本扫荡
                    #vip_status{trial_lv = VipLv, lv = RealLv, type = VipType} = VipStatus,
                    case lib_vip:get_vip_privilege(RealLv, VipType, VipLv, ?VIP_DUN_SWEEP, 1) of
                        Val when is_integer(Val) andalso Val =/= 0 ->
                            lib_dungeon_api:check_ever_finish(RoleId, DunId);
                        _A ->
                            {false, ?ERRCODE(err450_vip_limit)}
                    end;
                DunType == ?DUNGEON_TYPE_MATERIAL -> %% 材料副本扫荡评级限制
                    case lists:keyfind(?DUNGEON_REC_RATING, 1, DunRec) of
                        {_, MaxRating} -> ok;
                        _ -> MaxRating = 0
                    end,
                    MaxRating >= 5;
                true -> %% 其余默认日通关即可扫荡
                    lib_dungeon_api:check_today_passed(RoleId, DunId)
            end,
            case Res of
                true ->
                    sweep_common_check(Rest);
                false ->
                    if DunType == ?DUNGEON_TYPE_VIP ->
                            {false, ?ERRCODE(err610_conditon_not_enough)};
                        DunType == ?DUNGEON_TYPE_MATERIAL ->
                            {false, ?ERRCODE(err610_max_rating_limit)};
                        true ->
                            {false, ?ERRCODE(err610_today_not_pass)}
                    end;
                {false, Error} ->
                    {false, Error}
            end
    end;
sweep_common_check([{dun_flop_check, TmpFlop}|Rest]) ->
    #temp_flop{flop_time = FlopTime, flop_count = FlopCount} = TmpFlop,
    Now = utime:unixtime(),
    if Now < FlopTime andalso FlopCount < 1 ->
            {false, ?ERRCODE(err610_dun_flop_not_finish)};
        true ->
            sweep_common_check(Rest)
    end;
sweep_common_check([_|_Rest]) ->
    false.