%%%-------------------------------------------------------------------
%%% @author liushl
%%% @doc
%%%     物品背包操作
%%% @end
%%%-------------------------------------------------------------------
-module(lib_goods_do).
-author("liushl").
-include("goods.hrl").
-include("gift.hrl").
-include("common.hrl").
-include("def_goods.hrl").
-include("sql_goods.hrl").
-include("server.hrl").
-include("drop.hrl").
-include("attr.hrl").
-include("figure.hrl").
-include("errcode.hrl").
-include("def_module.hrl").
-include("language.hrl").
-include("guild.hrl").
-include("team.hrl").
-include("def_event.hrl").
-include("rec_event.hrl").
-include("predefine.hrl").
-include("scene.hrl").
-include("def_fun.hrl").
-include("goods_extra.hrl").
-export([
    get_goods_status/0,
    set_goods_status/1
]).

-export([
    login/4,
    init_data/1,
    handle_event/2,

    %% ------------------ 物品操作 ------------------
    use_goods/4,                   %% 使用物品
    throw_away/2,                  %% 销毁物品
    order_bag/2,                   %% 整理背包
    split/3,                       %% 拆分物品
    goods_decompose/2,             %% 分解物品
    sell_goods/3,                  %% 出售物品
    change_pos/4,                  %% 背包仓库相互移动
    goods_compose_or_evolution/7,   %% 物品合成/进化
    check_goods_bind_info/1,
    give_more_to_specify_loc/3,    %% 发放物品到指定背包
    move_a2b/3,                    %% 将单个物品从A背包移动到B背包
    move_more_a2b/3,               %% 将A背包物品移动到B背包，直到B背包没有空格子
    
    %% ------------------ 背包相关 ------------------
    expand_bag/3                   %% 扩展背包|仓库

]).

%% ---------------------------------------------------------------------------
%% @doc 上线初始化物品进程数据
-spec login(PlayerId, PlayerLv, CellNum, StorageNum) ->  Return when
    PlayerId    :: integer(),                           %% 玩家id
    PlayerLv    :: integer(),                           %% 玩家等级
    CellNum     :: integer(),                           %% 背包格子数
    StorageNum     :: integer(),                        %% 背包格子数
    Return      :: #goods_status{}.                     %% state记录
%% ---------------------------------------------------------------------------
login(PlayerId, PlayerLv, CellNum, StorageNum) ->
    GoodsMaps = lib_goods_init:init_goods_online(PlayerId, #{}, PlayerLv),
    GoodsStatus = #goods_status{
        player_id               = PlayerId,
        player_lv               = PlayerLv,
        dict                    = GoodsMaps,
        cell_num = CellNum,
        storage_num = StorageNum
    },
    GoodsStatus.

get_goods_status() ->
    GoodsStatus = get({?MODULE, player_goods_status}),
    GoodsStatus#goods_status{temp_bag = #{}}.

set_goods_status(GoodsStatus) ->
    put({?MODULE, player_goods_status}, GoodsStatus#goods_status{temp_bag = #{}}),
    ok.

%% 初始化物品状态数据
init_data(GoodsStatus) ->
    set_goods_status(GoodsStatus),
    ok.

%% 处理获得物品回调事件 -- 1获得立即使用物品
handle_event(PS, #event_callback{
    type_id = ?EVENT_GIVE_GOODS,
    data    = #callback_give_goods_data{
        type  = 1,
        goods = Goods
    }}) ->
    {_VipType, RealLv, TrialLv} = lib_vip_api:get_valid_vip_lv(PS),
    #goods{id = GoodsId, goods_id = GoodsType, num = GoodsNum} = Goods,
    Ret = if GoodsType == ?GOODS_ID_VIP_TRIAL_SP ->
            RealLv > 0 orelse TrialLv > 0;
        true ->
            true
    end,
    case Ret of
        true ->
            case pp_goods:handle(15050, PS, [GoodsId, GoodsType, GoodsNum]) of
                {ok, NewPS} -> {ok, NewPS};
                {ok, Value, NewPS} ->
                    mod_server:do_return_value(Value, NewPS),
                    {ok, NewPS};
                _ -> {ok, PS}
            end;
        _ -> {ok, PS}
    end;

handle_event(PS, _) ->
    {ok, PS}.

%%---------------------------------------------------------
%% 拆分物品
%%---------------------------------------------------------
split(GoodsId, GoodsTypeId, GoodsNum) ->
    GoodsStatus = lib_goods_do:get_goods_status(),
    case lib_goods_check:check_split(GoodsStatus, GoodsId, GoodsTypeId, GoodsNum) of
        {fail, Res} ->
            Res;
        {ok, GoodsInfo} ->
            case split_do(GoodsStatus, GoodsInfo, GoodsNum) of
                {ok, NewStatus, UpGoods} ->
                    lib_goods_do:set_goods_status(NewStatus),
                    lib_goods_api:notify_client(NewStatus#goods_status.player_id, UpGoods, split_goods),
                    ?SUCCESS;
                Error ->
                    ?ERR("mod_goods split error:~p", [Error]),
                    ?FAIL
            end
    end.
split_do(GoodsStatus, GoodsInfo, GoodsNum) ->
    F = fun() ->
        ok = lib_goods_dict:start_dict(),
        NewNum = GoodsInfo#goods.num - GoodsNum,
        [_, NewGoodsStatus] = goods_logic:change_goods_num(GoodsInfo, NewNum, GoodsStatus),
        NewInfo = GoodsInfo#goods{id = 0, num = GoodsNum},
        [_NewGoodsInfo, NewStatus1] = goods_logic:add_goods(NewInfo, NewGoodsStatus),
        {Dict, UpGoods} = lib_goods_dict:handle_dict_and_notify(NewStatus1#goods_status.dict),
        NewStatus2 = NewStatus1#goods_status{dict = Dict},
        {ok, NewStatus2, UpGoods}
        end,
    goods_transaction:transaction(F).
%%--------------------------------------------------
%% 物品分解
%% @param  PlayerStatus 玩家PS
%% @param  GoodsList    [{GoodsId, typeId, Num}]
%% @return              description
%%--------------------------------------------------
goods_decompose(PlayerStatus, GoodsList) ->
    GoodsStatus = lib_goods_do:get_goods_status(),
    case lib_goods_check:check_goods_decompose(GoodsStatus, GoodsList) of
        {fail, ErrorCode} ->
            {false, ErrorCode};
        {ok, GiveMatList} ->
            MergeGive = lib_goods_util:merge_same_goods(GiveMatList),
            %% 检查孩子玩具是否已经激活,未激活不可以分解
	        case lib_child_items:check_toy_active(PlayerStatus, GoodsList) of
				true ->
		            case lib_goods_api:delete_more_by_list(PlayerStatus, GoodsList, goods_decompose) of
		                1 ->
                            NewPlayer = lib_goods_api:send_reward(PlayerStatus, MergeGive, goods_decompose),
                            goods_decompose_log(NewPlayer, PlayerStatus, GoodsList, MergeGive),
                            {ok, NewPlayer};
		                ErrorCode ->
                            {false, ErrorCode}
		            end;
		        {false, Err} ->
                    {false, Err}
	        end
    end.

goods_decompose_log(Player, _PlayerOld, [{_, GoodsTypeId, _}|_] = GoodsList, _GiveList) ->
    CostList = [{CostType, CostNum} || {_, CostType, CostNum} <- GoodsList],
    GiveList = lib_goods_util:merge_same_goods(_GiveList),
    case data_goods_type:get(GoodsTypeId) of
        #ets_goods_type{type = ?GOODS_TYPE_WAR_SOUL} ->
            warsoul_logic:warsoul_decompose(Player, CostList, GiveList);
        #ets_goods_type{type = ?GOODS_TYPE_BABY} ->
            lib_child_items:log_toy_decompose(Player, CostList, GiveList);
        _ ->
            ok
    end.
%%--------------------------------------------------
%% 出售物品
%%--------------------------------------------------
sell_goods(PlayerStatus, ShopType, GoodsList) ->
    GoodsStatus = lib_goods_do:get_goods_status(),
    case check_sell(PlayerStatus, ShopType, GoodsList, GoodsStatus, [], []) of
        {fail, Res} ->
            [Res, PlayerStatus, []];
        {ok, MoneyList, SellList} ->
            %% 出售
            case sell_goods(PlayerStatus, GoodsStatus, MoneyList, SellList) of
                {ok, NewStatus, UpdateGoodsList, GoodsTypeList, RealMoneyL} ->
                    lib_goods_do:set_goods_status(NewStatus),
                    NewPlayerStatus = lib_goods_api:send_reward(PlayerStatus, RealMoneyL, sell_goods, 0),
                    lib_goods_api:notify_client_num(NewPlayerStatus#player_status.id, UpdateGoodsList),
                    %% 出售触发任务状态改变
                    lib_task_api:handle_task_goods_reduce(NewPlayerStatus, GoodsTypeList),
                    [?SUCCESS, NewPlayerStatus, GoodsTypeList];
                Error ->
                    ?ERR("sell_goods sell:~p~n", [Error]),
                    [?FAIL, PlayerStatus, []]
            end
    end.
sell_goods(PlayerStatus, Status, MomeyList, GoodsList) ->
    F = fun() ->
        ok = lib_goods_dict:start_dict(),
        case GoodsList of
            [{_, _}|_] ->
                {ok, NewStatus} = goods_del:delete_goods_list(Status, GoodsList);
            _ ->
                F1 = fun(OneSellL, {ok, TmpStatus}) ->
                    goods_del:delete_goods_list(TmpStatus, OneSellL)
                     end,
                {ok, NewStatus} = lists:foldl(F1, {ok, Status}, GoodsList)
        end,
        {Dict, GoodsL} = lib_goods_dict:handle_dict_and_notify(NewStatus#goods_status.dict),
        NewStatus2 = NewStatus#goods_status{dict = Dict},
        {GoodsTypeList, RealMomeyList} = log_sell_goods(GoodsList, MomeyList, PlayerStatus#player_status.id, [], []),
        {ok, NewStatus2, GoodsL, GoodsTypeList, RealMomeyList}
        end,
    goods_transaction:transaction(F).
make_log_sell_goods_args(GoodsList) ->
    F = fun({GoodsInfo, GoodsNum}, {TmpGTypeL, TmpGoodsIdL}) ->
        {[{GoodsInfo#goods.goods_id, GoodsNum}|TmpGTypeL], [{GoodsInfo#goods.id, GoodsNum}|TmpGoodsIdL]}
        end,
    lists:foldl(F, {[], []}, GoodsList).
log_sell_goods([{_, _}|_] = GoodsList, MomeyList, RoleId, _, _) ->
    {GoodsTypeList, GoodsIdList} = make_log_sell_goods_args(GoodsList),
    NewGoodsTypeList = lib_goods_api:trans_goods_format(GoodsTypeList),
    lib_log_api:log_goods_sell(RoleId, NewGoodsTypeList, GoodsIdList, MomeyList),
    {GoodsTypeList, MomeyList};
log_sell_goods([], _, _, GoodsTypeList, MomeyList) -> {GoodsTypeList, MomeyList};
log_sell_goods([OneSellL|GoodsList], [OneSellMoneyL|SellMoneyL], RoleId, GoodsTypeList, MomeyList) ->
    {TGoodsTypeList, TGoodsIdList} = make_log_sell_goods_args(OneSellL),
    NewTGoodsTypeList = lib_goods_api:trans_goods_format(TGoodsTypeList),
    lib_log_api:log_goods_sell(RoleId, NewTGoodsTypeList, TGoodsIdList, OneSellMoneyL),
    F = fun({MoneyType, MoneyId, MoneyNum}, Acc) ->
        case lists:keyfind(MoneyType, 1, Acc) of
            {MoneyType, MoneyId, PreNum} ->
                [{MoneyType, MoneyId, PreNum + MoneyNum}|lists:keydelete(MoneyType, 1, Acc)];
            _ ->
                [{MoneyType, MoneyId, MoneyNum}|Acc]
        end
        end,
    NewMomeyList = lists:foldl(F, MomeyList, OneSellMoneyL),
    F1 = fun({GTypeId, GoodsNum}, Acc) ->
        case lists:keyfind(GTypeId, 1, Acc) of
            {GTypeId, PreNum} ->
                [{GTypeId, PreNum + GoodsNum}|lists:keydelete(GTypeId, 1, Acc)];
            _ ->
                [{GTypeId, GoodsNum}|Acc]
        end
         end,
    NewGoodsTypeList = lists:foldl(F1, GoodsTypeList, TGoodsTypeList),
    log_sell_goods(GoodsList, SellMoneyL, RoleId, NewGoodsTypeList, NewMomeyList).
check_sell(_PlayerStatus, _ShopType, [], _GoodsStatus, SellList, MoneyList) ->
    {ok, MoneyList, SellList};
check_sell(PlayerStatus, ShopType, GoodsList, GoodsStatus, SellList, MoneyList) ->
    %% 分批出售,一次限制最多出售30件物品
    {SellL, RemainL} = ulists:sublist(GoodsList, 30),
    case lib_goods_check:check_sell(PlayerStatus, ShopType, SellL, GoodsStatus) of
        {fail, Res} -> {fail, Res};
        {ok, TmpMoneyL, TmpSellL} ->
            check_sell(PlayerStatus, ShopType, RemainL, GoodsStatus, [TmpSellL|SellList], [TmpMoneyL|MoneyList])
    end.
%%----------------------------------------------------------
%% 销毁物品
%%----------------------------------------------------------
throw_away(ThrowType, GoodsListArg) ->
    GoodsStatus = lib_goods_do:get_goods_status(),
    GoodsList = lib_goods_check:combine_goods_num_list(GoodsListArg),
    case lib_goods_check:check_throw_list(GoodsStatus, ThrowType, GoodsList) of
        {fail, Res} -> Res;
        {ok, GoodsInfoList} ->
            F = fun() ->
                ok = lib_goods_dict:start_dict(),
                {ok, NewStatus} = goods_del:delete_goods_list(GoodsStatus, GoodsInfoList),
                {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} ->
                    PlayerId = NewStatus#goods_status.player_id,
                    lib_goods_do:set_goods_status(NewStatus),
                    lib_goods_api:notify_client_num(PlayerId, UpdateGoodsList),
                    NowTime = utime:unixtime(),
                    ConsumeType = if
                                      ThrowType == ?THROW_TYPE_TIMEOUT -> goods_timeout;
                                      true -> throw
                                  end,
                    TypeId = data_goods:get_consume_type(ConsumeType),
                    LogList = [[NowTime, TypeId, PlayerId, GoodsId, GoodsTypeId, GoodsNum]
                        ||{#goods{id = GoodsId, goods_id = GoodsTypeId}, GoodsNum}<-GoodsInfoList],
                    lib_log_api:log_throw(LogList),
                    ?SUCCESS;
                Error ->
                    ?ERR("throw_away:~p", [Error]),
                    ?FAIL
            end
    end.
%%---------------------------------------------------
%% 使用物品
%% param: GoodsId   :: integer() 物品Id
%%        Num       :: integer() 物品数量
%% return:GoodsInfo :: #goods{}  物品信息
%%        NewNum    :: integer() 新的数量 失败返回0
%%---------------------------------------------------
use_goods(PlayerStatus, GoodsId, GoodsTypeId, GoodsNum) ->
    GoodsStatus = lib_goods_do:get_goods_status(),
    case lib_goods_check:check_use_goods(PlayerStatus, GoodsId, GoodsTypeId, GoodsNum, GoodsStatus) of
        {fail, Res} ->
            [false, Res];
        {ok, GoodsInfo, GiftInfo, Cost} -> %% 礼包使用
            case lib_gift_new:use_gift(PlayerStatus, GoodsStatus, GoodsInfo, GiftInfo, GoodsNum, Cost) of
                {ok, NewPlayerStatus, NewStatus, NewNum, GiveList} ->
                    lib_goods_do:set_goods_status(NewStatus),
                    [?SUCCESS, NewPlayerStatus, NewNum, GiveList];
                Error ->
                    ?ERR("goods use_gift error:~p", [Error]),
                    [false, ?FAIL]
            end;
        {ok, GoodsInfo} -> %% 物品
            TransReturn =
                case lib_goods_use:use_goods(PlayerStatus, GoodsStatus, GoodsInfo, GoodsNum) of
                    {ok, NewPlayerStatus, UseNum} ->
                        [?SUCCESS, NewPlayerStatus, UseNum];
    
                    {use_fashion_color_goods, NewPlayerStatus, UseNum, Errcode} ->
                        [Errcode, NewPlayerStatus, UseNum];
    
                    {use_designtion_good, NewPlayerStatus, UseNum, _Coin} ->
                        [ignore, NewPlayerStatus, UseNum];
                    {use_sp_vip_goods, NewPlayerStatus, UseNum} ->
                        [ignore, NewPlayerStatus, UseNum];
    
                    {_, NewPlayerStatus, UseNum} ->
                        [?SUCCESS, NewPlayerStatus, UseNum];
    
                    {fail, Res2} ->
                        [false, Res2];
    
                    Error ->
                        ?ERR("mod_goods RoleId:~p, use_goods:~p, GoodsInfo:~p~n",
                            [PlayerStatus#player_status.id, Error, GoodsInfo#goods.goods_id]),
                        [false, ?FAIL]
                end,
            case TransReturn of
                [false, Res] ->
                    [false, Res];
                [Res, NewPlayer, CostNum] ->
                    lib_log_api:log_throw(goods_use, PlayerStatus#player_status.id, GoodsInfo#goods.id, GoodsInfo#goods.goods_id, GoodsNum, 0, 0),
                    [Res, NewPlayer, GoodsInfo#goods.num - CostNum, []]
            end
    end.

%%----------------------------------------------------------
%% 扩展背包
%%----------------------------------------------------------
expand_bag(PlayerStatus, Pos, CellNum) ->
    case lib_goods_check:check_expand_bag(PlayerStatus, Pos, CellNum) of
        {fail, Res} ->
            [Res, PlayerStatus];
        {ok, Cost} ->
            case lib_goods_api:cost_objects_with_auto_buy(PlayerStatus, Cost, extend_bag, [Pos, CellNum]) of
                {true, Player, _} ->
                    GoodsStatus = lib_goods_do:get_goods_status(),
                    case Pos of
                        ?GOODS_LOC_BAG ->
                            NewGoodsStatus = GoodsStatus#goods_status{cell_num = GoodsStatus#goods_status.cell_num + CellNum},
                            NewPlayer = lib_goods_util:extend_bag(Player, CellNum);
                        _->
                            NewGoodsStatus = GoodsStatus#goods_status{storage_num = GoodsStatus#goods_status.storage_num + CellNum},
                            NewPlayer = lib_storage_util:extend_storage(Player, CellNum)
                    end,
                    lib_goods_do:set_goods_status(NewGoodsStatus),
                    [1, NewPlayer];
                {false, Err, _} ->
                    [Err, PlayerStatus]
            end
    end.

%%----------------------------------------------------------
%% 背包仓库相互移动 GoodId:唯一id
%%----------------------------------------------------------
change_pos(Ps, GoodId, FromPos, ToPos)->
    GoodsStatus = lib_goods_do:get_goods_status(),
    case lib_goods_check:check_good_change_pos(Ps, GoodsStatus, GoodId, FromPos, ToPos) of
        {fail, Res} -> Res;
        {ok, GoodsInfo} ->
            case catch move_goods_pos(GoodsStatus, GoodsInfo, ToPos) of
                {ok, NewGoodsStatus, UpGoods} ->
                    lib_goods_do:set_goods_status(NewGoodsStatus),
                    lib_goods_api:notify_client(Ps#player_status.id, UpGoods, bag_move),
                    1;
                _Error ->
                    ?ERR("_Error:~p~n", [_Error]),
                    0
            end
    end.
%% 物品存入某个位置
move_goods_pos(GoodsStatus, GoodsInfo, Location) ->
    F = fun() ->
            ok = lib_goods_dict:start_dict(),
            [_NewGoodsInfo, NewGoodsStatus] = goods_logic:change_goods_location(GoodsInfo, Location, 0, GoodsStatus),
            {Dict, UpGoods} = lib_goods_dict:handle_dict_and_notify(NewGoodsStatus#goods_status.dict),
            {ok, NewGoodsStatus#goods_status{dict = Dict}, UpGoods}
        end,
    goods_transaction:transaction(F).
%%--------------------------------------------------------------
%% 整理背包
%%--------------------------------------------------------------
order_bag(PlayerStatus, Pos) ->
    GoodsStatus = lib_goods_do:get_goods_status(),
    GoodsList = lib_goods_util:get_goods_list(PlayerStatus#player_status.id, Pos, GoodsStatus#goods_status.dict),
    %% 按物品类型ID排序
    GoodsList1 = lib_goods_util:sort(GoodsList, bind_id),
    case GoodsList1 of
        [One|Last] ->
            F = fun() -> merge_goods(Last, [{One#goods.id, One}], false) end,
            case goods_transaction:transaction(F) of
                {ok, _, false} ->
                    [2];
                {ok, NewGoodsList, _Bool} ->
                    NewGoodsMaps = lib_goods_util:put_location_goods(GoodsStatus#goods_status.dict, Pos, dict:from_list(NewGoodsList)),
                    lib_goods_do:set_goods_status(GoodsStatus#goods_status{dict = NewGoodsMaps}),
                    [1];
                Error ->
                    ?ERR("goods order error:~p", [Error]),
                    [0]
            end;
        _ ->
            [2]
    end.

%% 将相邻物品合并
merge_goods([OldGoods|OldT], [{NewKey, NewGoods}|NewT], Bool) ->
    OldKey = OldGoods#goods.id,
    case lib_goods_util:can_overlap_same_cell(NewGoods, OldGoods) of
        true ->
            case data_goods_type:get(NewGoods#goods.goods_id) of
                #ets_goods_type{max_overlap = MaxOverLap} ->
                    NewGoodsNum = NewGoods#goods.num,
                    case NewGoodsNum >= MaxOverLap of
                        true  -> %% 已经放满了，就继续判断下一个
                            merge_goods(OldT, [{OldKey, OldGoods}, {NewKey, NewGoods}|NewT], Bool);
                        false -> %% 还可以放一点
                            OldGoodsNum = OldGoods#goods.num,
                            StillCanPut = MaxOverLap - NewGoodsNum,
                            case OldGoodsNum =< StillCanPut of
                                true  -> %% 可以全部合并过来，旧物品可以删除
                                    lib_goods_util:delete_goods(OldGoods#goods.id, OldGoods#goods.player_id),
                                    lib_goods_util:change_goods_num(NewGoods, NewGoodsNum + OldGoodsNum),
                                    merge_goods(OldT, [{NewKey, NewGoods#goods{num = NewGoodsNum+OldGoodsNum}}|NewT], true);
                                false -> %% 合并一部分后，新物品就满了
                                    lib_goods_util:change_goods_num(NewGoods, MaxOverLap),
                                    lib_goods_util:change_goods_num(OldGoods, OldGoodsNum - StillCanPut),
                                    merge_goods(OldT, [{OldKey, OldGoods#goods{num = OldGoodsNum - StillCanPut}}, {NewKey, NewGoods#goods{num = MaxOverLap}}|NewT], true)
                            end
                    end;
                _ ->
                    merge_goods(OldT, NewT, Bool)
            end;
        false ->
            merge_goods(OldT, [{OldKey, OldGoods}, {NewKey, NewGoods}|NewT], Bool)
    end;
merge_goods([], GoodsList, Bool) ->
    {ok, GoodsList, Bool}.

%%--------------------------------------------------
%% @doc 物品合成进化
%%--------------------------------------------------
goods_compose_or_evolution_check(RuleId, MainGoodsId, MainGoodsLocation, CostList, Times, Player) ->
    case MainGoodsId =:= 0 of
        true  ->
            Config = data_goods_compose_evolution:get_goods_compose_evolution(RuleId),
            goods_compose_or_evolution_check_do(Config, 0, CostList, Times, Player);
        false ->
            case lib_goods_api:get_goods_info(MainGoodsId, MainGoodsLocation) of
                #goods{} = GoodsInfo ->
                    Config = data_goods_compose_evolution:get_goods_compose_evolution(RuleId),
                    goods_compose_or_evolution_check_do(Config, GoodsInfo, CostList, Times, Player);
                _ ->
                    {false, ?ERRCODE(err150_no_goods)}
            end
    end.

goods_compose_or_evolution_check_do([], _, _, _, _) -> {false, ?ERRCODE(missing_config)};
goods_compose_or_evolution_check_do(Config, MainGoodsInfo, CostList, Times, Player) ->
    #base_goods_compose_or_evolution_info{
        target_goods_id = TargetGoodsId
        , classify_id = ClassifyId
        , main_goods_id = MainGoods
        , cost_money = CostMoney
        , condition = Condition
    } = Config,
    %% 主材料是否存在
    CheckMainGoods = case MainGoodsInfo =:= 0 of
                         true  -> true;
                         false ->
                             MainGoodsInfo#goods.goods_id =:= MainGoods
                     end,
    %% 合成开放条件
    CheckCondition = goods_compose_evolution:goods_compose_or_evolution_check_condition(Condition, Player),
    %% 剩余背包空间
    CheckBagSize = case MainGoodsInfo =/= 0 of
                       true  ->
                           %% 由原物品进化，不占背包
                           true;
                       false when TargetGoodsId =/= 0 ->
                           %% 常规合成
                           case data_goods_type:get(TargetGoodsId) of
                               #ets_goods_type{bag_location = BagLocation} ->
                                   lib_goods_api:get_cell_num(Player, BagLocation) > 0;
                               _ ->
                                   error
                           end;
                       false ->
                           %% TODO 其他合成，判断普通背包或者后面自行判断
                           lib_goods_api:get_cell_num(Player) > 0
                   end,
    %% 多次是否有效
    CheckTimes = case MainGoodsInfo =:= 0 of
                     true  -> true;
                     false ->
                         %% 物品进化默认只能处理一次
                         Times =:= 1
                 end,
    %% 钱财
    CheckMoney = lib_goods_api:check_object_list(Player, lib_goods_util:goods_object_multiply_by(CostMoney, Times)),
    if
        not CheckMainGoods -> {false, ?ERRCODE(err150_no_goods)};
        CheckCondition =/= true -> CheckCondition;
        CheckBagSize =:= error -> {false, ?ERRCODE(miss_config)};
        CheckBagSize =:= false -> {false, ?ERRCODE(err150_no_cell)};
        not CheckTimes -> {false, ?ERRCODE(system_busy)};
        CheckMoney =/= true -> CheckMoney;
        true ->
            %% 分类进行判断m
            goods_compose_evolution:goods_compose_or_evolution_check_by_classify(ClassifyId, Config, MainGoodsInfo, CostList, Times, Player)
    end.

%% 物品合成/进化
goods_compose_or_evolution(RuleId, MainGoodsId, MainGoodsLocation, CostList, Times, Player, ShopBuy) ->
    case goods_compose_or_evolution_check(RuleId, MainGoodsId, MainGoodsLocation, CostList, Times, Player) of
        {false, Err} ->
            {false, Err};
        {ok, Config, Ratio, MainGoodsInfo, CostMoney, _CheckGoodsList, CostGoodsList, TargetInfo, TrueTimes} ->
            CheckGoodsList = lib_goods_util:merge_same_goods(_CheckGoodsList),
            %% 如果有需要去商城购买东西的
            case ShopBuy =/= [] of
                true  ->
                    case lib_shop:shop_type_check(Player, ShopBuy) of
                        {false, Code} ->
                            {false, Code};
                        {true, BuyCostList, BuyGoodsList} ->
                            %% 即将购买这些物品，将消耗品减去这些东西，再判断消耗是否足够
                            StillCost =  minus_goods(CheckGoodsList, BuyGoodsList),
                            case lib_goods_api:check_object_list(Player, CostMoney ++ BuyCostList ++ StillCost) of
                                true  ->
                                    %% 可以，那就先去买东西
                                    {ok, Player1} = lib_shop:buy_goods_by_money_type(Player, ShopBuy, 2),
                                    goods_compose_or_evolution_then(Player1, CostMoney, CostGoodsList, MainGoodsInfo, TargetInfo, TrueTimes, Ratio, Config, 1);
                                {false, Err} ->
                                    {false, Err}
                            end
                    end;
                false ->
                    %% 不需要买东西，直接扣东西
                    case lib_goods_api:check_object_list(Player, CostMoney ++ CheckGoodsList) of
                        true  ->
                            goods_compose_or_evolution_then(Player, CostMoney, CostGoodsList, MainGoodsInfo, TargetInfo, TrueTimes, Ratio, Config, 0);
                        {false, Err} ->
                            {false, Err}
                    end
            end
    end.

%% 扣东西合成
goods_compose_or_evolution_then(Player, CostMoney, CostGoodsList, MainGoodsInfo, TargetInfo, TrueTimes, Ratio, Config, AutoBuy) ->
    case lib_goods_api:cost_object_list(Player, CostMoney ++ CostGoodsList, goods_compose, "") of
        {false, Err, _} ->
            {false, Err};
        {true, Player1} ->
            Success = Ratio >= urand:rand(1, 10000),
            goods_compose_or_evolution_do(Success, MainGoodsInfo, CostGoodsList, TargetInfo, TrueTimes, Player1, Config, CostMoney ++ CostGoodsList, AutoBuy)
    end.

%% 失败
goods_compose_or_evolution_do(false, MainGoodsInfo, _CostGoodsList, _TargetInfo, _Times, Player, Config, Cost, AutoBuy) ->
    log_compose_evolution(Player, MainGoodsInfo, Config, Cost, AutoBuy, 2),
    {fail, Player};
%% 成功  合成
goods_compose_or_evolution_do(true, 0, CostGoodsList, TargetGoodsId, Times, Player, Config, Cost, AutoBuy) ->
    GoodsType = check_goods_bind_info(CostGoodsList),
    GoodsInfo = [{GoodsType, TargetGoodsId, Times}],
    Player1 = lib_goods_api:send_reward(Player, GoodsInfo, goods_compose),
    %% 合成成功处理
    Player2 = goods_compose_evolution:goods_evolution_after_by_classify(Config, Player1, 0, GoodsInfo),
    %% 装备任务
    Player3 = equipment_task:event_equipment_evolution(Player2, TargetGoodsId),
    log_compose_evolution(Player3, 0, Config, Cost, AutoBuy, 1),
    {goods_compose, Player3, GoodsInfo, TargetGoodsId};
%% 成功 进化
goods_compose_or_evolution_do(true, MainGoodsInfo, _CostGoodsList, TargetGoodsId, _Times, Player, Config, Cost, AutoBuy) ->
    FromGoods = MainGoodsInfo,
    NewGoodsInfo = lib_goods_util:get_new_goods(data_goods_type:get(TargetGoodsId)),
    NewGoodsInfo1 = NewGoodsInfo#goods{
        id = FromGoods#goods.id,
        player_id = FromGoods#goods.player_id,
        location = FromGoods#goods.location,
        cell = FromGoods#goods.cell,
        num = 1
    },
    %% 判断进化特殊处理
    NewGoodsInfo2 = goods_compose_evolution:goods_evolution_by_classify(Config,FromGoods, NewGoodsInfo1),
    goods_logic:update_goods_info([NewGoodsInfo2], [], none),
    %% 合成成功处理
    Player1 = goods_compose_evolution:goods_evolution_after_by_classify(Config,Player, FromGoods, NewGoodsInfo2),
    log_compose_evolution(Player, MainGoodsInfo, Config, Cost, AutoBuy, 1),
    {goods_evolution, Player1, NewGoodsInfo2, TargetGoodsId}.
 
log_compose_evolution(Player, MainGoodsInfo, Config, Cost, AutoBuy, Result) ->
    #player_status{id = RoleId, figure = Figure} = Player,
    #base_goods_compose_or_evolution_info{classify_id = ClassifyId, subclass = SubClass, target_goods_id = TargetGoods} = Config,
    CostList =
        [
            case One of
                {_, _, _} -> One;
                {#goods{goods_id = GoodsId}, Num} -> {0, GoodsId, Num};
                _ -> One
            end
            || One <- Cost
        ],
    FinalCost =
    case MainGoodsInfo of
        #goods{goods_id = MainGoods} -> [{0, MainGoods, 1}|CostList];
        _ -> CostList
    end,
    lib_log_api:log_compose_evolution(
        [RoleId, Figure#figure.name, Figure#figure.lv, ClassifyId, SubClass, TargetGoods,
            util:term_to_bitstring(FinalCost), AutoBuy, Result, utime:unixtime()]
    ).

check_goods_bind_info([{#goods{bind = ?BIND}, _}|_]) -> ?TYPE_BIND_GOODS;
check_goods_bind_info([{#goods{bind = ?UNBIND}, _}|T]) -> check_goods_bind_info(T);
check_goods_bind_info([{_, GoodsId, _}|T]) ->
    case data_goods_type:get(GoodsId) of
        #ets_goods_type{bind = 1} -> ?TYPE_BIND_GOODS;
        #ets_goods_type{bind = 0} -> check_goods_bind_info(T)
    end;
check_goods_bind_info([]) -> ?TYPE_GOODS.

minus_goods(GoodsList, DelList) ->
    lists:foldl(
        fun({_, GoodsId, GoodsNum}, Temp) ->
            case lists:keyfind(GoodsId, 2, Temp) of
                {_, _, NeedNum} when GoodsNum >= NeedNum ->
                    lists:keydelete(GoodsId, 2, Temp);
                {Type, _, NeedNum} ->
                    lists:keyreplace(GoodsId, 2, Temp, {Type, GoodsId, NeedNum - GoodsNum});
                _ ->
                    Temp
            end
        end, GoodsList, DelList
    ).
%% 发物品到指定背包
%% 某些特定活动才能调用这个接口！！！！！！！！
%% GoodsList = [{location, Location, GoodsTypeId, GoodsNum }, ...]
give_more_to_specify_loc(Location, GoodsList, Type) ->
    GoodsStatus = lib_goods_do:get_goods_status(),
    case lib_goods_check:check_give_to_specify_loc(Location, GoodsList) of
        ok ->
            F = fun() ->
                ok = lib_goods_dict:start_dict(),
                {ok, NewStatus} = lib_goods_check:list_handle(fun goods_add:give_goods/2, 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(NewStatus#goods_status.player_id, UpdateGoodsList, Type),
                    {1, UpdateGoodsList};
                %% 物品类型不存在
                {db_error, {error,{_, not_found}}} ->
                    2;
                %% 背包格子不足
                {db_error, {error,{cell_num, not_enough}}} ->
                    3;
                %% 动态属性设置权限不足
                {db_error, {error,{_Type, cannot_overlap}}} ->
                    4;
                %% 背包类型配置错误
                {db_error, {error,{GTypeId, bag_location_fail}}} ->
                    ?ERR("bag_location_fail error GTypeId:~p", [GTypeId]),
                    ?ERRCODE(err150_bag_location_fail);
                Error ->
                    ?ERR("give_more error:~p", [Error]),
                    Error
            end;
        {false, duplicate} -> %% 列表中GoodsTypeId重复
            5;
        {false, ErrorCode} ->
            ErrorCode
    end.

%%--------------------------------------------------
%% 把物品从A背包移动到B背包
%% @param  GoodsStatus #goods_status{}
%% @param  GoodsInfo   #goods{}
%% @param  ToLoc       B背包位置
%% @returns             {ok, #goods_status{}, UpdateGoodsList}
%%--------------------------------------------------
move_a2b(GoodsStatus, GoodsInfo, ToLoc) ->
    F = fun() ->
        ok = lib_goods_dict:start_dict(),
        case move_a2b_do({GoodsInfo, ToLoc}, GoodsStatus) of
            {ok, NewGoodsStatus} ->
                {Dict, UpGoods} = lib_goods_dict:handle_dict_and_notify(NewGoodsStatus#goods_status.dict),
                LastGoodsStatus = NewGoodsStatus#goods_status{dict = Dict},
                {ok, LastGoodsStatus, UpGoods};
            _ ->
                {ok, GoodsStatus, []}
        end
        end,
    goods_transaction:transaction(F).

move_more_a2b(GoodsStatus, GoodsInfoList, ToLoc) ->
    NewGoodsInfoList = [{T, ToLoc} || T <- GoodsInfoList],
    F = fun() ->
        ok = lib_goods_dict:start_dict(),
        %% 如果匹配错误了通过事务还原数据
        {ok, NewGoodsStatus} = lib_goods_check:list_handle(fun move_a2b_do/2, GoodsStatus, NewGoodsInfoList),
        {Dict, UpGoods} = lib_goods_dict:handle_dict_and_notify(NewGoodsStatus#goods_status.dict),
        LastGoodsStatus = NewGoodsStatus#goods_status{dict = Dict},
        {ok, LastGoodsStatus, UpGoods}
    end,
    goods_transaction:transaction(F).

move_a2b_do({GoodsInfo, ToLoc}, GoodsStatus) ->
    [_NewGoodsInfo, NewGoodsStatus] = goods_logic:change_goods_location(GoodsInfo, ToLoc, 0, GoodsStatus),
    {ok, NewGoodsStatus}.
