%% ----------------------------------
%% desc     :器灵寻宝-商店模块 
%% module   :lib_lattice_shop.erl
%% author   :hh
%% time     :20/06/29
%% ----------------------------------

-module(lib_lattice_shop).

-export([login/1]).
-export([logout/1]).
-export([handle_event/2]).

-export([
    shopping/2,
    reset_shop/1
    ]).

-include("common.hrl").
-include("errcode.hrl").
-include("server.hrl").
-include("figure.hrl").
-include("def_event.hrl").
-include("def_goods.hrl").
-include("def_module.hrl").
-include("rec_event.hrl").
-include("marble.hrl").

login(RoleId) ->
    case db:get_row(?ROLE_LATTICE_SHOP_SELECT, [RoleId]) of
        [ShopCount, ShopTime, ShopInfo|_] ->
            RoleLatticeShop = #role_lattice_shop{
                shop_count = ShopCount,
                shop_time = ShopTime,
                shop_info = util:bitstring_to_term(ShopInfo)
            },
            RoleLatticeShop;
        _ ->
            #role_lattice_shop{}
    end.

logout(Player) ->
    #player_status{id = RoleId, role_lattice_shop = RoleLatticeShop} = Player,
    #role_lattice_shop{online_cross_day = CrossDay} = RoleLatticeShop,
    CrossDay == 1 andalso sql_update(RoleId, RoleLatticeShop),
    ok.

sql_update(RoleId, RoleLatticeShop) ->
    #role_lattice_shop{
        shop_count = ShopCount,
        shop_time  = ShopTime,
        shop_info  = ShopInfo
    } = RoleLatticeShop,
    InfoBin = util:term_to_bitstring(ShopInfo),
    db:execute(?ROLE_LATTICE_REPLACE, [RoleId, ShopCount, ShopTime, InfoBin]),
    ok.

handle_event(Player, #event_callback{type_id = ?EVENT_ZERO_CLOCK}) ->
    #player_status{role_lattice_shop = RoleLatticeShop} = NewPlayer = shop_update(Player, daily_reset),
    NewPlayer2 = NewPlayer#player_status{role_lattice_shop = RoleLatticeShop#role_lattice_shop{online_cross_day = 1}},
    pp_marble:handle(41405, NewPlayer2, []),
    {ok, NewPlayer2};
handle_event(Player, #event_callback{type_id = ?EVENT_LOGIN_CAST}) ->
    #player_status{role_lattice_shop = RoleLatticeShop, figure = #figure{lv = RoleLv}} = Player,
    #role_lattice_shop{shop_info = ShopInfo, shop_time = ShopTime} = RoleLatticeShop,
    case ShopInfo of
        [_|_] ->
            NewRoleLatticeShop = do_daily_update_lattice(ShopTime, RoleLatticeShop),
            NewPlayer = Player#player_status{role_lattice_shop = NewRoleLatticeShop},
            {ok, NewPlayer};
        _ ->
            CfgLv = lib_module:get_open_lv(?MOD_MARBLE),
            if RoleLv >= CfgLv ->
                    NewPlayer = shop_update(Player, daily_reset),
                    {ok, NewPlayer};
                true ->
                    {ok, Player}
            end
    end;
handle_event(Player, #event_callback{type_id = ?EVENT_LV_UP}) ->
    #player_status{id = RoleId, figure = #figure{lv = RoleLv}, role_lattice_shop = RoleLatticeShop} = Player,
    ConfigLv = lib_module:get_open_lv(?MOD_MARBLE),
    if RoleLv =:= ConfigLv ->
            #role_lattice_shop{shop_time = ShopTime} = RoleLatticeShop,
            NewRoleLatticeShop = do_daily_update_lattice(ShopTime, RoleLatticeShop),
            sql_update(RoleId, NewRoleLatticeShop),
            NewPlayer = Player#player_status{role_lattice_shop = NewRoleLatticeShop},
            pp_marble:handle(41405, NewPlayer, []),
            {ok, NewPlayer};
        true ->
            {ok, Player}
    end;
handle_event(Player, _) ->
    {ok, Player}.

shopping(Player, Index) ->
    #player_status{sid = Sid} = Player,
    case shopping_check(Player, Index) of
        {true, cost, Goods, Cost} ->
            case lib_goods_api:cost_object_list_with_check(Player, Cost, marble_shop_cost, "") of
                {true, NewPlayer, _} ->
                    do_shopping(NewPlayer, Goods, Index);
                {false, ErrCode, _} ->
                    lib_server_send:send_to_sid(Sid, pt_414, 41406, [ErrCode]),
                    ok
            end;
        {true, free, Goods, _} ->
            do_shopping(Player, Goods, Index);
        {false, ErrCode} ->
            lib_server_send:send_to_sid(Sid, pt_414, 41406, [ErrCode]),
            ok
    end.

reset_shop(Player) ->
    case reset_shop_check(Player) of
        {true, Cost} ->
            do_reset_shop(Player, Cost);
        {false, ErrCode} ->
            lib_server_send:send_to_sid(Player#player_status.sid, pt_414, 41407, [ErrCode])
    end.

do_shopping(Player, Goods, Index) ->
    #player_status{id = RoleId, sid = Sid, role_lattice_shop = RoleLatticeShop} = Player,
    #role_lattice_shop{shop_info = ShopInfo} = RoleLatticeShop,
    NewShopInfo = lists:keyreplace(Index, 1, ShopInfo, {Index, ?MARBLE_SHOP_GETED}),
    NewRoleLatticeShop = RoleLatticeShop#role_lattice_shop{
        shop_info = NewShopInfo, shop_time = utime:unixtime(), online_cross_day = 0},
    sql_update(RoleId, NewRoleLatticeShop),
    NewPlayer   = lib_goods_api:send_reward(Player, Goods, marble_shop_buy),
    NewPlayer1  = NewPlayer#player_status{role_lattice_shop = NewRoleLatticeShop},
    lib_server_send:send_to_sid(Sid, pt_414, 41406, [?SUCCESS]),
    {ok, NewPlayer1}.

do_reset_shop(Player, Cost) ->
    case lib_goods_api:cost_object_list_with_check(Player, Cost, marble_shop_reset_cost, "") of
        {true, NewPlayer, _} ->
            do_reset_shop_logic(NewPlayer);
        {false, ErrCode, _} ->
            lib_server_send:send_to_sid(Player#player_status.sid, pt_414, 41407, [ErrCode]),
            ok
    end.

do_reset_shop_logic(Player) ->
    #player_status{sid = Sid, role_lattice_shop = RoleLatticeShop} = Player,
    NewRoleLatticeShop = RoleLatticeShop#role_lattice_shop{shop_time = utime:unixtime()},
    NewPlayer = Player#player_status{role_lattice_shop = NewRoleLatticeShop},
    #player_status{id = RoleId, role_lattice_shop = NewRoleLatticeShop1} = NewPlayer1 = shop_update(NewPlayer, manual_reset),
    sql_update(RoleId, NewRoleLatticeShop1),
    lib_server_send:send_to_sid(Sid, pt_414, 41407, [?SUCCESS]),
    {ok, NewPlayer1}.

shop_update(Player = #player_status{}, ResetType) ->
    #player_status{role_lattice_shop = RoleLatticeShop} = Player,
    #role_lattice_shop{shop_count = ShopCount} = RoleLatticeShop,
    NewShopInfo   = shop_update_do(),
    NewShopCount  = update_shop_reset_count(ShopCount, ResetType),
    NewRoleLatticeShop = RoleLatticeShop#role_lattice_shop{
        shop_count = NewShopCount, shop_info = NewShopInfo, shop_time = utime:unixtime(), online_cross_day = 0},
    Player#player_status{role_lattice_shop = NewRoleLatticeShop};
shop_update(RoleLatticeShop = #role_lattice_shop{}, ResetType) ->
    #role_lattice_shop{shop_count = ShopCount} = RoleLatticeShop,
    NewShopInfo   = shop_update_do(),
    NewShopCount  = update_shop_reset_count(ShopCount, ResetType),
    RoleLatticeShop#role_lattice_shop{
        shop_count = NewShopCount, shop_info = NewShopInfo, shop_time = utime:unixtime(), online_cross_day = 0}.

shop_update_do() ->
    AllIndexs = data_marble:get_all_index(),
    {FreeIndexs, PayIndexs} = get_sorted_index(AllIndexs),
    FreeIndex = get_avaliable_index(free, FreeIndexs),
    PayIndex  = get_avaliable_index(pay, PayIndexs),
    ShopIndex = lists:append([FreeIndex, PayIndex]),
    ShopIndex.

update_shop_reset_count(ShopCount, ResetType) ->
    if ResetType == daily_reset -> 
            0;
        true ->
            ShopCount+1
    end.

get_sorted_index(AllIndexs) ->
    lists:foldl(fun(Index, {Acc1, Acc2}) ->
        case data_marble:get_goods_info(Index) of
            #base_equip_shop{is_pay = 0, weight_val = Val} ->
                {[{Val, Index}|Acc1], Acc2};
            #base_equip_shop{is_pay = 1, weight_val = Val} ->
                {Acc1, [{Val, Index}|Acc2]};
            _ ->
                {Acc1, Acc2}
        end
     end, {[], []}, AllIndexs).

get_avaliable_index(Type, Indexs) ->
    Num = case Type of
        free ->
            data_marble:get_lattice_kv(shop_free_num);
        _ ->
            data_marble:get_lattice_kv(shop_pay_num)
    end,
    RandIndexs = urand:list_rand_by_weight(Indexs, Num),
    [{Index, ?MARBLE_SHOP_UNGET} || Index <- RandIndexs].

shopping_check(Player, Index) ->
    #player_status{role_lattice_shop = RoleLatticeShop} = Player,
    #role_lattice_shop{shop_info = ShopInfo} = RoleLatticeShop,
    CheckL = [
        {shop_index_config, Index},
        {shop_index_check, Index, ShopInfo}
    ],
    case do_check(CheckL) of
        true ->
            #base_equip_shop{
                goods = Goods, price = Price
            } = data_marble:get_goods_info(Index),
            if Price == 0 ->
                    case is_free_shop(ShopInfo) of
                        true ->
                            {false, ?ERRCODE(err414_shop_config)};
                        _ -> %% false
                            {true, free, Goods, []}
                    end;
                true ->
                    {true, cost, Goods, [{?TYPE_GOLD, 0, Price}]}
            end;
        {false, ErrCode} ->
            {false, ErrCode}
    end.

is_free_shop(ShopInfo) ->
    FreeShoppedNum = lists:foldl(fun({Index, State}, Acc) ->
        case data_marble:get_goods_info(Index) of
            #base_equip_shop{is_pay = 0} when State == ?MARBLE_SHOP_GETED ->
                Acc+1;
            _ ->
                Acc
        end
     end, 0, ShopInfo),
    ConfigNum = data_marble:get_lattice_kv(shop_free_num),
    if FreeShoppedNum >= ConfigNum ->
            true;
        true ->
            false
    end.

reset_shop_check(Player) ->
    #player_status{role_lattice_shop = RoleLatticeShop} = Player,
    #role_lattice_shop{shop_count = ShopCount} = RoleLatticeShop,
    ResetCosts = data_marble:get_lattice_kv(shop_reset_cost),
    NewShopCount = ShopCount+1,
    case calc_reset_cost(NewShopCount, ResetCosts) of
        Cost = [_|_] ->
            case lib_goods_api:check_object_list(Player, Cost) of
                true ->
                    {true, Cost};
                {false, ErrCode} ->
                    {false, ErrCode}
            end;
        {false, ErrCode} ->
            {false, ErrCode}
    end.

calc_reset_cost(ShopCount, ResetCosts) ->
    [{MinCount, Cost}|Rest] = lists:keysort(1, ResetCosts),
    if ShopCount < MinCount -> 
            {false, ?ERRCODE(err414_shop_reset)};
        true ->
            do_calc_reset_cost(ShopCount, Rest, Cost)
    end.

do_calc_reset_cost(_ShopCount, [], Cost) -> [Cost];
do_calc_reset_cost(ShopCount, [{ConfigCount, ConfigCost}|Rest], Cost) ->
    if ShopCount >= ConfigCount -> 
            do_calc_reset_cost(ShopCount, Rest, ConfigCost);
        true -> 
            [Cost]
    end.

do_daily_update_lattice(Time, RoleLatticeShop) ->
    case utime:is_today(Time) == true of
        true ->
            RoleLatticeShop;
        _ ->
            shop_update(RoleLatticeShop, daily_reset)
    end.


do_check([]) ->
    true;
do_check([{shop_index_config, Index}|Rest]) ->
    case data_marble:get_goods_info(Index) of
        #base_equip_shop{} ->
            do_check(Rest);
        _ ->
            {false, ?ERRCODE(err414_shop_config)}
    end;
do_check([{shop_index_check, Index, ShopInfo}|Rest]) ->
    case lists:keyfind(Index, 1, ShopInfo) of
        {_, ?MARBLE_SHOP_GETED} ->
            {false, ?ERRCODE(err414_has_receive)};
        {_, ?MARBLE_SHOP_UNGET} ->
            do_check(Rest);
        _ ->
            {false, ?ERRCODE(err414_shop_config)}
    end;
do_check([_DataShop|_Rest]) ->
    {false, ?FAIL}.