%%%-------------------------------------------------------------------
%%% @author liushl
%%% @doc
%%%     物品删除内部处理逻辑，常规调用使用lib_goods_api里的接口
%%% @end
%%%-------------------------------------------------------------------
-module(goods_del).
-author("liushl").
-include("common.hrl").
-include("goods.hrl").
-include("def_goods.hrl").
-include("sql_goods.hrl").
-include("server.hrl").
-include("sell.hrl").
-include("sql_player.hrl").
-include("predefine.hrl").
-include("figure.hrl").
-include("errcode.hrl").
-include("def_fun.hrl").
-include("def_id_create.hrl").
-include("attr.hrl").
-include("def_event.hrl").
-include("rec_event.hrl").
-include("def_module.hrl").
-include("skill.hrl").
-include("rec_achievement.hrl").
-include("arena.hrl").
-compile(export_all).
%% API
-export([]).
-define(FORBID_USE_FGOLD_LIST, [pay_sell, pay_tax, pay_auction, login_return_reward_buy]).

%% ---------------------------------------------------------------------------
%% @doc 判断是否满足消耗列表
-spec check_object_list(PS, ObjectList) ->  Return when
    PS             :: #player_status{},         %% #player_status{}
    ObjectList     :: list(),                   %% object_list :: [{type,goods_id,num}]
    Return         :: true | {false, integer()}.%% 返回：true|{false,错误码}
%% ---------------------------------------------------------------------------
check_object_list(PS, ObjectList) ->
    check_object_list(PS, ObjectList, none).

check_object_list(PS, ObjectList, ConsumeType) ->
    ObjectList2 = lib_goods_api:trans_object_list(ObjectList),
    do_check_object_list(PS, ObjectList2, ConsumeType).

do_check_object_list(_PS, [], _ConsumeType) -> true;
do_check_object_list(PS, [H|T], ConsumeType) ->
    case check_object(PS, H, ConsumeType) of
        true -> do_check_object_list(PS, T, ConsumeType);
        {false, Res} -> {false, Res}
    end.

%% 要扣除的物品数量需要大于0,不然提示错误
check_object(PS, { {?TYPE_GOODS, GoodsId}, GoodsNum}, _ConsumeType) when GoodsNum > 0 ->
    case check_goods_num(PS, [{GoodsId, GoodsNum}]) of
        1 -> true;
        _ -> {false, ?GOODS_NOT_ENOUGH}
    end;
check_object(PS, { {?TYPE_BIND_GOODS, GoodsId}, GoodsNum}, _ConsumeType) when GoodsNum > 0 ->
    case check_goods_num(PS, [{GoodsId, GoodsNum}]) of
        1 -> true;
        _ -> {false, ?GOODS_NOT_ENOUGH}
    end;
check_object(PS, {{?TYPE_MATE, _GoodsId}, GoodsNum}, _ConsumeType) when GoodsNum > 0 ->
    case is_enough_currency(PS, ?GOODS_ID_MATE, GoodsNum) of
        true -> true;
        false -> {false, data_goods:get_money_not_enough_error(?TYPE_MATE)}
    end;
check_object(PS, {{?TYPE_CHILD_TOY, _GoodsId}, GoodsNum}, _ConsumeType) when GoodsNum > 0 ->
    case is_enough_currency(PS, ?GOODS_ID_CHILD_TOY, GoodsNum) of
        true -> true;
        false -> {false, data_goods:get_money_not_enough_error(?TYPE_CHILD_TOY)}
    end;
check_object(PS, {{?TYPE_WORKROOM, _GoodsId}, GoodsNum}, _ConsumeType) when GoodsNum > 0 ->
	case is_enough_currency(PS, ?GOODS_ID_FASHION_COIN, GoodsNum) of
		true -> true;
		false -> {false, data_goods:get_money_not_enough_error(?TYPE_WORKROOM)}
	end;
check_object(PS, {{?TYPE_CURRENCY, CurrencyId}, GoodsNum}, _ConsumeType) when GoodsNum > 0 ->
    case is_enough_currency(PS, CurrencyId, GoodsNum) of
        true -> true;
        false -> {false, ?ERRCODE(money_not_enough)}
    end;
check_object(PS, {{?TYPE_EXP, _GoodsId}, GoodsNum}, _ConsumeType) when GoodsNum > 0 ->
    case lib_player:is_enough_exp(PS, GoodsNum) of
        true -> true;
        false -> {false, ?EXP_NOT_ENOUGH}
    end;
check_object(PS, {{?TYPE_STAR, _GoodsId}, GoodsNum}, _ConsumeType) when GoodsNum > 0 ->
    case lib_sup_vip:is_enough_star(PS, GoodsNum) of
        true -> true;
        false -> {false, ?ERRCODE(star_no_enough)}
    end;
check_object(PS, {{?TYPE_LEGION, _GoodsId}, GoodsNum}, _ConsumeType) when GoodsNum > 0 ->
    case lib_role_legion:is_enough_arms(PS, GoodsNum) of
        true -> true;
        false -> {false, data_goods:get_money_not_enough_error(?TYPE_LEGION)}
    end;
check_object(PS, {{MoneyType, _GoodsId}, GoodsNum}, ConsumeType) when GoodsNum > 0 ->
    case is_enough_money(PS, GoodsNum, MoneyType, ConsumeType) of
        true -> true;
        false ->
            {false, data_goods:get_money_not_enough_error(MoneyType)}
    end;
check_object(_PS, { {_Type, _GoodsId}, _GoodsNum}, _ConsumeType) ->
    ?ERR("unkown object:~p~n", [{ {_Type, _GoodsId}, _GoodsNum}]),
    {false, ?FAIL}.

%% ---------------------------------------------------------------------------
%% @doc 判断物品列表数量
%% GoodsTypeList = [{GoodsTypeId, Num}, {goods, GoodsTypeId, Num}, {?TYPE_GOODS, GoodsTypeId, GoodsNum}]
%% return: 0失败，1 成功
check_goods_num(_PlayerInfo, GoodsTypeList) ->
    NewGoodsTypeList = lib_goods_api:trans_goods_format(GoodsTypeList),
    GoodsStatus = lib_goods_do:get_goods_status(),
    case check_goods_num_do(NewGoodsTypeList, GoodsStatus) of
        {ok, 1} -> 1;
        _ -> 0
    end.
check_goods_num_do([], _) ->
    {ok, 1};
check_goods_num_do([{GoodsTypeId, GoodsNum}|H], GoodsStatus) ->
    case data_goods_type:get(GoodsTypeId) of
        #ets_goods_type{bag_location = BagLocation} ->
            GoodsList = lib_goods_util:get_type_goods_list(GoodsStatus#goods_status.player_id, GoodsTypeId, BagLocation, GoodsStatus#goods_status.dict, GoodsStatus#goods_status.player_lv),
            TotalNum  = lib_goods_util:get_goods_total_num(GoodsList),
            case TotalNum >= GoodsNum of
                true ->
                    check_goods_num_do(H, GoodsStatus);
                false ->
                    not_enough
            end;
        _ ->
            tool:back_trace_to_file(),
            ?ERR("check_goods_num err: goods_type_id = ~p err_config", [GoodsTypeId]),
            not_enough
    end.

%%----------------------------------------------------
%% 计算余额够不够 true为充足，false为不足
%%----------------------------------------------------
is_enough_money(PlayerStatus, Cost, MoneyType) ->
    is_enough_money(PlayerStatus, Cost, MoneyType, none).

is_enough_money(PlayerStatus, Cost, MoneyType, ConsumeType) ->
    IsForbidFGold = lists:member(ConsumeType, ?FORBID_USE_FGOLD_LIST),
    case MoneyType of
        ?TYPE_BGOLD ->
            (PlayerStatus#player_status.bgold + PlayerStatus#player_status.fgold
                + PlayerStatus#player_status.gold) >= Cost;
        ?TYPE_FGOLD ->
            PlayerStatus#player_status.fgold >= Cost;
        ?TYPE_COIN ->
            PlayerStatus#player_status.coin >= Cost;
        ?TYPE_GOLD when IsForbidFGold ->
            PlayerStatus#player_status.gold >= Cost;
        ?TYPE_GOLD ->
            (PlayerStatus#player_status.gold + PlayerStatus#player_status.fgold) >= Cost;
        ?TYPE_HONOUR ->
            PlayerStatus#player_status.honour >= Cost;
        ?TYPE_GFAME ->
            PlayerStatus#player_status.gfame >= Cost;
        ?TYPE_STAR ->
            lib_sup_vip:is_enough_star(PlayerStatus, Cost);
        _ ->
            false
    end.

is_enough_currency(PS, CurrencyId, Num) ->
    case maps:find(CurrencyId, PS#player_status.currency_map) of
        {ok, Value} ->
            Value >= Num;
        _ ->
            false
    end.
%% ---------------------------------------------------------------------------
%% @doc 扣除消耗列表object_list
-spec cost_object_list(PS, ObjectList, Type, About) ->  Return when
    PS             :: #player_status{},         %% #player_status{}
    ObjectList     :: list(),                   %% object_list :: [{type,goods_id,num}]
    Type           :: atom(),                   %% 物品|货币消耗类型：需要后台定义"消耗类型"
    About          :: string(),                 %% 消耗描述
    Return         :: {true, #player_status{}}|{false, integer(), #player_status{}}. %% 返回：{true, PS}|{false,错误码,PS}
%% ---------------------------------------------------------------------------
cost_object_list(PS, [], _Type, _About) ->
    {true, PS};
cost_object_list(PS, [H|T], Type, About) ->
    case cost_object(PS, H, Type, About) of
        {true, NewPS} ->
            cost_object_list(NewPS, T, Type, About);
        {false, Res} ->
            {false, Res, PS}
    end.

cost_object(PS, {?TYPE_GOODS, GoodsId, GoodsNum}, Type, _About) ->
    case goods_delete_type_list(PS, [{GoodsId, GoodsNum}], Type) of
        1 -> {true, PS};
        _ -> {false, ?FAIL}
    end;
cost_object(PS, {?TYPE_BIND_GOODS, GoodsId, GoodsNum}, Type, _About) ->
    cost_object(PS, {?TYPE_GOODS, GoodsId, GoodsNum}, Type, _About);
cost_object(PS, {GoodsInfo, GoodsNum}, Type, _About) when is_record(GoodsInfo, goods)->
    case lib_goods_api:delete_more_by_list(PS, [{GoodsInfo, GoodsNum}], Type) of
        1 -> {true, PS};
        _ -> {false, ?FAIL}
    end;
cost_object(PS, {GoodsId, GoodsNum}, Type, _About) ->
    case goods_delete_type_list(PS, [{GoodsId, GoodsNum}], Type) of
        1 -> {true, PS};
        _ -> {false, ?FAIL}
    end;
cost_object(PS, {?TYPE_GOLD, _GoodsId, GoodsNum}, Type, About) ->
    NewPS = cost_money(PS, GoodsNum, ?TYPE_GOLD, Type, About),
    {true, NewPS};
cost_object(PS, {?TYPE_BGOLD, _GoodsId, GoodsNum}, Type, About) ->
    NewPS = cost_money(PS, GoodsNum, ?TYPE_BGOLD, Type, About),
    {true, NewPS};
cost_object(PS, {?TYPE_COIN, _GoodsId, GoodsNum}, Type, About) ->
    NewPS = cost_money(PS, GoodsNum, ?TYPE_COIN, Type, About),
    {true, NewPS};
cost_object(PS, {?TYPE_GFAME, _GoodsId, GoodsNum}, Type, About) ->
    NewPS = cost_money(PS, GoodsNum, ?TYPE_GFAME, Type, About),
    {true, NewPS};
cost_object(PS, {?TYPE_LEGION, _GoodsId, GoodsNum}, Type, About) ->
    NewPS = cost_money(PS, GoodsNum, ?TYPE_LEGION, Type, About),
    {true, NewPS};
cost_object(PS, {?TYPE_HONOUR, _GoodsId, GoodsNum}, Type, About) ->
    NewPS = cost_money(PS, GoodsNum, ?TYPE_HONOUR, Type, About),
    {true, NewPS};
cost_object(PS, {?TYPE_MATE, _GoodsId, GoodsNum}, Type, About) ->
    NewPS = cost_currency(PS, ?GOODS_ID_MATE, GoodsNum, Type, About),
    {true, NewPS};
cost_object(PS, {?TYPE_CHILD_TOY, _GoodsId, GoodsNum}, Type, About) ->
    NewPS = cost_currency(PS, ?GOODS_ID_CHILD_TOY, GoodsNum, Type, About),
    {true, NewPS};
cost_object(PS, {?TYPE_WORKROOM, _GoodsId, GoodsNum}, Type, About) ->
    NewPS = cost_currency(PS, ?GOODS_ID_FASHION_COIN, GoodsNum, Type, About),
    {true, NewPS};
cost_object(PS, {?TYPE_CURRENCY, CurrencyId, GoodsNum}, Type, About) ->
    NewPS = cost_currency(PS, CurrencyId, GoodsNum, Type, About),
    {true, NewPS};
cost_object(PS, {?TYPE_EXP, _GoodsId, GoodsNum}, Type, About) ->
    NewPS = lib_player:deduct_exp(PS, GoodsNum, Type, About),
    {true, NewPS};
cost_object(PS, {?TYPE_STAR, _, GoodsNum}, Type, About) ->
    NewPS = lib_sup_vip:cost_star(PS, GoodsNum, Type, About),
    {true, NewPS};
cost_object(_PS, {_Type, _GoodsId, _GoodsNum}, _Type, _About) ->
    ?ERR("unkown object:~p", [_Type]),
    {false, ?FAIL}.

%% ---------------------------------------------------------------------------
%% @doc  删除背包物品 根据物品唯一Id删除物品
delete_by_id(GoodsId, GoodsTypeId, GoodsNum) ->
    GoodsStatus = lib_goods_do:get_goods_status(),
    delete_by_id_2(GoodsStatus, GoodsId, GoodsTypeId, GoodsNum).

delete_by_id_2(GoodsStatus, GoodsId, GoodsTypeId, GoodsNum) ->
    case lib_goods_check:check_delete(GoodsStatus, GoodsId, GoodsTypeId, GoodsNum) of
        {fail, Res} -> {Res, {}};
        {ok, GoodsInfo} ->
            case delete_one(GoodsInfo, [GoodsStatus, GoodsNum]) of
                [NewStatus, _] ->
                    lib_goods_do:set_goods_status(NewStatus),
                    NewNum = GoodsInfo#goods.num - GoodsNum,
                    NewGoodsInfo = GoodsInfo#goods{num = NewNum},
                    PlayerId = NewStatus#goods_status.player_id,
                    lib_goods_api:notify_client_num(PlayerId, [NewGoodsInfo]),
                    {1, GoodsInfo};
                Error ->
                    ?ERR("mod_goods delete_one:~p", [Error]),
                    {0, {}}
            end
    end.
%% ---------------------------------------------------------------------------
%% @doc  删除背包物品列表  根据物品唯一Id列表删除物品
%% GoodsList   :: [{GoodsId, GoodsTypeId, DeleteNum}]
delete_list([{_GoodsId, _GoodsTypeId, _DeleteNum}|_] = GoodsList) ->
    GoodsStatus = lib_goods_do:get_goods_status(),
    delete_list_2(GoodsStatus, GoodsList);
delete_list([{_GoodsInfo, _DeleteNum}|_] = GoodsList) ->
    GoodsStatus = lib_goods_do:get_goods_status(),
    NewGoodsList = lib_goods_check:combine_goods_num_list(GoodsList),
    delete_goods_info_list(GoodsStatus, NewGoodsList).

delete_list_2(GoodsStatus, GoodsList0) ->
    GoodsList = lib_goods_check:combine_goods_num_list(GoodsList0),
    case lib_goods_check:check_delete_list(GoodsStatus, GoodsList) of
        {fail, Res} -> {Res, []};
        {ok, NewGoodsList} ->
            delete_goods_info_list(GoodsStatus, NewGoodsList)
    end.

delete_goods_info_list(GoodsStatus, GoodsList) ->
    F = fun() ->
        ok = lib_goods_dict:start_dict(),
        {ok, NewStatus} = delete_goods_list(GoodsStatus, GoodsList),
        {Dict, GoodsL} =
            lib_goods_dict:handle_dict_and_notify(NewStatus#goods_status.dict),
        NewStatus2 = NewStatus#goods_status{dict = Dict},
        {ok, NewStatus2, GoodsL}
        end,
    case goods_transaction:transaction(F) of
        {ok, NewStatus, UpdateGoodsList} ->
            lib_goods_do:set_goods_status(NewStatus),
            lib_goods_api:notify_client_num(NewStatus#goods_status.player_id, UpdateGoodsList),
            {1, GoodsList};
        Error ->
            ?ERR("mod_goods delete_list:~p", [Error]),
            {0, []}
    end.

delete_goods_list(GoodsStatus, GoodsList) ->
    F1 = fun({GoodsInfo, GoodsNum}, AccGoodsList) ->
        GoodsId = GoodsInfo#goods.id,
        NewAccGoodsNum = case lists:keyfind(GoodsInfo#goods.id, 1, AccGoodsList) of
                             {GoodsId, _AccGoodsInfo, AccGoodsNum} -> AccGoodsNum + GoodsNum;
                             _ -> GoodsNum
                         end,
        lists:keystore(GoodsId, 1, AccGoodsList, {GoodsId, GoodsInfo, NewAccGoodsNum})
         end,
    NewGoodsList = lists:foldl(F1, [], GoodsList),
    CheckFun = fun({_GoodsId, GoodsInfo, GoodsNum}) -> GoodsInfo#goods.num >= GoodsNum end,

    %% 按物品唯一Id合并物品,再次检查数量是否满足
    case lists:all(CheckFun, NewGoodsList) of
        true ->
            F2 = fun({_GoodsId, GoodsInfo, GoodsNum}, Status1) ->
                [Status2, _] = delete_one(GoodsInfo, [Status1, GoodsNum]),
                Status2
                 end,
            NewStatus = lists:foldl(F2, GoodsStatus, NewGoodsList),
            {ok, NewStatus};
        false ->
            %% Player:玩家, GoodsError:物品错误
            NeedGoodsList = [{GoodsInfo#goods.goods_id, GoodsNum}||
                {_GoodsId, GoodsInfo, GoodsNum}<-NewGoodsList],
            ?ERR("Player:~p, GoodsError:~p~n", [GoodsStatus#goods_status.player_id,  NeedGoodsList]),
            throw(goods_error)
    end.
%% ---------------------------------------------------------------------------
%% @doc 根据物品类型Id列表删除物品并刷新客户端以及做物品日志
-spec goods_delete_type_list(PlayerInfo, GoodsTypeList, Type) -> Res when
    PlayerInfo  :: integer() | #player_status{},    %% 玩家Id或者玩家记录
    GoodsTypeList:: [{GoodsTypeId, DeleteNum}|{goods, GoodsTypeId, DeleteNum}|{?TYPE_GOODS, GoodsTypeId, DeleteNum}],     %% 物品列表
    GoodsTypeId :: integer(),                       %% 物品类型Id
    DeleteNum   :: integer(),                       %% 要删除的数量
    Type        :: atom(),                          %% 物品消耗类型
    %% 需要后台定义"产出消耗类型--消耗类型"
    Res         :: integer().                       %% 结果码 0:失败|1:成功
%% ---------------------------------------------------------------------------
goods_delete_type_list(PlayerInfo, GoodsTypeList, Type) when GoodsTypeList=/=[] ->
    NewGoodsTypeList = lib_goods_api:trans_goods_format(GoodsTypeList),
    Res = delete_type_list(NewGoodsTypeList),
    case Res==1 andalso Type=/=[] of
        true ->
            NowTime = utime:unixtime(),
            ConsumeTypeId = data_goods:get_consume_type(Type),
            LogList = [[NowTime, ConsumeTypeId, PlayerInfo#player_status.id, 0, GoodsTypeId, DeleteNum]
                ||{GoodsTypeId, DeleteNum}<-NewGoodsTypeList],
            lib_log_api:log_throw(LogList);
        false ->
            ok
    end,
    Res;
goods_delete_type_list(_PlayerInfo, GoodsTypeList, _Type) ->
    ?ERR("~p:~p param error:~p", [?MODULE, ?LINE, GoodsTypeList]),
    0.

%% 删除多类物品 根据物品类型Id列表删除物品
%% GoodsTypeListArg = [{GoodsTypeId1,GoodsNum}, {GoodsTypeId2,GoodsNum}, ...]
delete_type_list(GoodsTypeListArg) ->
    GoodsStatus = lib_goods_do:get_goods_status(),
    GoodsTypeList = lib_goods_check:combine_goods_num_list(GoodsTypeListArg),
    case lib_goods_check:check_delete_type_list(GoodsStatus, GoodsTypeList) of
        {fail} -> 0;
        {ok} ->
            Fun = fun() ->
                ok = lib_goods_dict:start_dict(),
                F = fun goods_del:delete_type_list_goods/2,
                case lib_goods_check:list_handle(F, GoodsStatus, GoodsTypeList) of
                    {ok, NewStatus} ->
                        {Dict, GoodsL} =
                            lib_goods_dict:handle_dict_and_notify(NewStatus#goods_status.dict),
                        NewStatus2 = NewStatus#goods_status{dict = Dict},
                        {ok, NewStatus2, GoodsL};
                    _ ->
                        throw({error, {not_enough}})
                end
                  end,
            case goods_transaction:transaction(Fun) of
                {ok, NewStatus, UpdateGoodsList} ->
                    lib_goods_do:set_goods_status(NewStatus),
                    lib_goods_api:notify_client_num(NewStatus#goods_status.player_id, UpdateGoodsList),
                    1;
                _ ->
                    0
            end
    end.

%% 删除一类物品的指定数量
%% @spec delete_type_list_goods({GoodsTypeId,GoodsNum}, GoodsStatus) -> {ok, NewStatus} | Error
delete_type_list_goods({GoodsTypeId, GoodsNum}, GoodsStatus) ->
    case data_goods_type:get(GoodsTypeId) of
        #ets_goods_type{bag_location = BagLocation} ->
            GoodsList = lib_goods_util:get_type_goods_list(GoodsStatus#goods_status.player_id, GoodsTypeId, BagLocation, GoodsStatus#goods_status.dict, GoodsStatus#goods_status.player_lv),
            TotalNum  = lib_goods_util:get_goods_total_num(GoodsList),
            case TotalNum >= GoodsNum of
                true ->
                    delete_more(GoodsStatus, GoodsList, GoodsNum);
                false ->
                    not_enough
            end;
        _ ->
            ?ERR("delete_type_list_goods err: goods_type_id = ~p err_config", [GoodsTypeId]),
            not_enough
    end.
delete_type_list_goods_as_much_as_possible({GoodsTypeId, GoodsNum}, GoodsStatus) ->
    case data_goods_type:get(GoodsTypeId) of
        #ets_goods_type{bag_location = BagLocation} ->
            GoodsList = lib_goods_util:get_all_type_goods_list(GoodsTypeId, BagLocation, GoodsStatus#goods_status.dict),
            TotalNum  = lib_goods_util:get_goods_total_num(GoodsList),
            case TotalNum >= GoodsNum of
                true ->
                    delete_more(GoodsStatus, GoodsList, GoodsNum);
                false ->
                    delete_more(GoodsStatus, GoodsList, TotalNum)
            end;
        _ ->
            ?ERR("delete_type_list_goods err: goods_type_id = ~p err_config", [GoodsTypeId]),
            not_enough
    end.
%% 删除多个物品 优先删除限时的 然后绑定的
delete_more(Status, GoodsList, GoodsNum) ->
    {List1, List2} = split_into_two(GoodsList),
    GoodsList1 = lib_goods_util:sort(List1, expire_time),
    GoodsList2 = lib_goods_util:sort(List2, bind),
    [NewStatus, _] = lists:foldl(fun delete_one/2, [Status, GoodsNum], GoodsList1 ++ GoodsList2),
    {ok, NewStatus}.
split_into_two(GoodsList) ->
    NowTime = utime:unixtime(),
    split_into_two(NowTime, GoodsList, [], []).

split_into_two(_NowTime, [], Lists1, Lists2) -> {Lists1, Lists2};
split_into_two(NowTime, [Goods|Rest], Lists1, Lists2) ->
    case Goods#goods.expire_time > 0  of
        true ->
            case Goods#goods.expire_time > NowTime of
                true -> split_into_two(NowTime, Rest, [Goods|Lists1], Lists2);
                false -> split_into_two(NowTime, Rest, Lists1, Lists2)
            end;
        false -> split_into_two(NowTime, Rest, Lists1, [Goods|Lists2])
    end.

%%-------------------------------------------------------------------------------------------
%% @doc 删除物品，在同一个物品上删除指定数量，如果不够则全部删除，并且返回剩余要删除的物品数量
%% -spec delete_one(GoodsInfo, [GoodsStatus, GoodsNum]) -> [NewGoodsStatus, NewNum]
%% GoodsInfo                        :: #goods{}         物品记录
%% GoodsStatus|NewGoodsStatus       :: #goods_status{}  物品进程状态
%% GoodsNum | NewNum                :: integer()        物品要删除数量 | 还待删除的物品数量
%% @end
%%-------------------------------------------------------------------------------------------
delete_one(GoodsInfo, [GoodsStatus, GoodsNum]) ->
    if GoodsNum > 0 andalso GoodsInfo#goods.id > 0 ->
        case GoodsInfo#goods.num > GoodsNum of
            true ->
                NewNum = GoodsInfo#goods.num - GoodsNum,
                [_NewGoodsInfo, NewStatus] = goods_logic:change_goods_num(GoodsInfo, NewNum, GoodsStatus),
                [NewStatus, 0];
            false ->
                NewNum = GoodsNum - GoodsInfo#goods.num,
                NewStatus = goods_logic:delete_goods(GoodsInfo, GoodsStatus),
                [NewStatus, NewNum]
        end;
        true ->
            [GoodsStatus, GoodsNum]
    end;

delete_one(GoodsInfo, [GoodsStatus, GoodsNum, DelList]) ->
    if GoodsNum > 0 andalso GoodsInfo#goods.id > 0 ->
        case GoodsInfo#goods.num > GoodsNum of
            true ->
                NewNum = GoodsInfo#goods.num - GoodsNum,
                goods_logic:change_goods_num(GoodsInfo, NewNum, GoodsStatus),
                [GoodsStatus, 0, [{GoodsInfo,GoodsNum}|DelList]];
            false ->
                NewNum = GoodsNum - GoodsInfo#goods.num,
                NewStatus = goods_logic:delete_goods(GoodsInfo, GoodsStatus),
                [NewStatus, NewNum, [{GoodsInfo,GoodsInfo#goods.num}|DelList]]
        end;
        true ->
            [GoodsStatus, GoodsNum, DelList]
    end.
%% ---------------------------------------------------------------------------
%% @doc 扣钱
-spec cost_money(PlayerStatus, Cost, MoneyType, Type, About) ->  Return when
    PlayerStatus   :: #player_status{},   %% #player_status{}
    Cost           :: integer(),          %% 数量
    MoneyType      :: atom(),             %% 货币类型
    Type           :: atom(),             %% 货币消耗类型：需要后台定义"产出消耗类型--消耗类型"
    About          :: string(),           %% 扣钱描述
    Return         :: #player_status{}.   %% #player_status{}
%% ---------------------------------------------------------------------------
cost_money(PlayerStatus, Cost, MoneyType, Type, About) ->
    NewPlayerStatus1 = do_cost_money(PlayerStatus, Cost, MoneyType, Type),
    if
        Type=/=[] andalso Type=/=none ->
            lib_log_api:log_consume(Type, MoneyType, PlayerStatus, NewPlayerStatus1, About);
        true -> skip
    end,
    NewPlayerStatus1.

%%-----------------------------------------------------------
%% @doc 扣钱,不够钱会抛出错误,调用前要判断是否够钱
%%【注】
%% 没有日志：不要直接调用cost_money(PlayerStatus, Cost, MoneyType)
%% 调用cost_money(PlayerStatus, Cost, MoneyType, Type, About)
-spec do_cost_money(PlayerStatus, Cost, MoneyType, Type) -> Return when
    PlayerStatus    :: #player_status{},   %% 玩家记录
    Cost            :: integer(),          %% 消耗的数量
    MoneyType       :: integer(),          %% 类型
    Type            :: atom(),             %% 货币消耗类型：需要后台定义"产出消耗类型--消耗类型"
    Return          :: #player_status{}.   %% #player_status{}
%% ------------------------------------------------------------
do_cost_money(PlayerStatus, Cost, MoneyType, Type) ->
    #player_status{gold = Gold, bgold = BGold, fgold = FGold,gfame=GFame, coin = Coin, honour = Honour} = PlayerStatus,
    IsForbidFGold = lists:member(Type, ?FORBID_USE_FGOLD_LIST),
    case MoneyType of
        ?TYPE_COIN -> % 铜钱
            lib_daily:plus_count(PlayerStatus#player_status.id, ?MOD_GOODS, ?GOODS_COUNTER_DAILY_COIN_COST, Cost),
            NewPlayerStatus = PlayerStatus#player_status{coin = (Coin - Cost)};
        ?TYPE_BGOLD ->
            lib_daily:plus_count(PlayerStatus#player_status.id, ?MOD_GOODS, ?GOODS_COUNTER_DAILY_BGOLD_COST, Cost),
            NewPlayerStatus = do_cost_gold(PlayerStatus, Cost);
        ?TYPE_FGOLD ->
            NewPlayerStatus = PlayerStatus#player_status{fgold = (FGold - Cost)};
        ?TYPE_GFAME ->
            NewFame = max(0,GFame - Cost),
            lib_achievement_api:guild_donate_use_event(PlayerStatus, Cost),
            NewPlayerStatus = PlayerStatus#player_status{gfame = NewFame};
        ?TYPE_GOLD when IsForbidFGold ->
            NewPlayerStatus = PlayerStatus#player_status{gold = (Gold - Cost)};
        ?TYPE_GOLD ->
            lib_daily:plus_count(PlayerStatus#player_status.id, ?MOD_GOODS, ?GOODS_COUNTER_DAILY_GOLD_COST, Cost),
            NewPlayerStatus = case FGold >= Cost of
                                  true -> PlayerStatus#player_status{fgold = (FGold - Cost)};
                                  false -> PlayerStatus#player_status{fgold = 0, gold = (FGold + Gold - Cost)}
                              end;
        ?TYPE_HONOUR ->
            lib_daily:plus_count(PlayerStatus#player_status.id, ?MOD_GOODS, ?GOODS_COUNTER_DAILY_HONOUR_COST, Cost),
            NewPlayerStatus = PlayerStatus#player_status{honour = (Honour - Cost)};
        ?TYPE_STAR ->
            NewPlayerStatus = lib_sup_vip:cost_star(PlayerStatus, Cost, Type, "");
        ?TYPE_LEGION ->
            NewPlayerStatus = lib_role_legion:cost_legion_arms(PlayerStatus, Cost, Type, "")
    end,
    %判断金钱数
    if  NewPlayerStatus#player_status.coin < 0  orelse NewPlayerStatus#player_status.bgold < 0
        orelse NewPlayerStatus#player_status.fgold < 0 orelse NewPlayerStatus#player_status.gold < 0
        orelse NewPlayerStatus#player_status.honour < 0 ->
        %% Playeer:玩家,  MoneyError:金钱错误
        Error = ulists:concat(["Player：",NewPlayerStatus#player_status.id," ",
            NewPlayerStatus#player_status.figure#figure.name,
            " MoneyError：coin=", NewPlayerStatus#player_status.coin,
            ", bgold=",NewPlayerStatus#player_status.bgold,
            ", gold=",NewPlayerStatus#player_status.gold,
            ", honour=",NewPlayerStatus#player_status.honour
        ]),
        throw({money_error, Error});
        true ->
            skip
    end,
    lib_player:update_player_money(PlayerStatus, NewPlayerStatus),
    lib_player:send_attribute_change_notify(NewPlayerStatus, ?NOTIFY_MONEY),
    lib_consume_data:update_money_consume(NewPlayerStatus, PlayerStatus, Type),
    lib_player_event:async_dispatch(NewPlayerStatus#player_status.pid, ?EVENT_MONEY_CONSUME,
        #callback_money_cost{consume_type = Type, money_type = MoneyType, cost = Cost,
            args = #{old_coin => Coin, old_bgold => BGold, old_fgold => FGold,old_gfame => GFame, old_gold => Gold, old_honour => Honour}}),
    NewPlayerStatus.

do_cost_gold(PlayerStatus, Cost) ->
    #player_status{gold = Gold, bgold = BGold, fgold = FGold, coin = _Coin} = PlayerStatus,
    case {BGold >= Cost, (BGold + FGold) >= Cost} of
        {true, _} ->
            NewPlayerStatus = PlayerStatus#player_status{bgold = (BGold - Cost)};
        {false, true} ->
            NewPlayerStatus = PlayerStatus#player_status{bgold = 0, fgold = (BGold + FGold - Cost)};
        _ ->
            NewPlayerStatus = PlayerStatus#player_status{bgold = 0, fgold = 0, gold = (BGold + FGold + Gold - Cost)}
    end,
    NewPlayerStatus.

cost_currency(PS, CurrencyId, Num, Type, About) ->
    #player_status{currency_map = CMap, id = PlayerId, figure = #figure{lv = Lv, vip = VipLv}} = PS,
    case maps:find(CurrencyId, CMap) of
        {ok, Value} when Value >= Num andalso Num > 0 ->
            NewValue = Value - Num,
            SQL = io_lib:format(?SQL_UPDATE_CURRENCY, [NewValue, PlayerId, CurrencyId]),
            db:execute(SQL),
            if
                Type=/=[] andalso Type=/=none ->
                    lib_log_api:log_consume_currency(PlayerId, Lv, VipLv, Type, CurrencyId, Num, NewValue, About);
                true -> skip
            end,
            NewPS = PS#player_status{currency_map = CMap#{CurrencyId => NewValue}},
            goods_logic:send_update_currency(NewPS, CurrencyId),
            NewPS;
        _ ->
            throw(money_error)
    end.
