%%%--------------------------------------
%%% @Module  : lib_vip_util
%%% @Author  : ywf
%%% @Created : 2018-8-23
%%% @Description:  vip
%%%--------------------------------------
-module(lib_vip_util).
-include("server.hrl").
-include("figure.hrl").
-include("errcode.hrl").
-include("relationship.hrl").
-include("vip.hrl").
-include("predefine.hrl").
-include("common.hrl").
-include("shop.hrl").
-include("def_goods.hrl").
-include("def_module.hrl").
-include("def_event.hrl").
-include("goods.hrl").
-include("def_fun.hrl").
-include("attr.hrl").
-include("customer_service.hrl").
-include("def_vip.hrl").
-include("def_daily.hrl").
-include("language.hrl").
-include("role_foster.hrl").

-export ([
        check_buy_privilege/3
        ,use_vip_goods/3
        ,check_active_sup_vip/3
        ,check_sup_vip_exchange/4
        ,check/1
    ]).

-export([
    get_vip_lv_db/1,
    db_select_vip/1,
    db_update_vip/2
    ]).

-export([
    gm_reset_vip/2
    ]).


use_vip_goods(PlayerStatus, GoodsInfo, GoodsNum) ->
    IsExpAddGoods = lists:member(GoodsInfo#goods.goods_id, ?VIP_EXP_GOODS),
    IsTrialGoods  = lists:member(GoodsInfo#goods.goods_id, ?VIP_TRIAL_GOODS),
    if IsExpAddGoods ->
            add_vip_exp(PlayerStatus, GoodsInfo, GoodsNum);
        IsTrialGoods ->
            active_trial_vip(PlayerStatus, GoodsInfo, GoodsNum);
        true ->
            {fail, ?FAIL}
    end.

add_vip_exp(PlayerStatus, GoodsInfo, GoodsNum) ->
    if GoodsInfo#goods.num >= GoodsNum ->
            UseNum = GoodsNum;
        true ->
            UseNum = GoodsInfo#goods.num
    end,
    if UseNum =/= 0 ->
            GoodsVipExp = data_vip:get_cfg(1),
            case lists:keyfind(GoodsInfo#goods.goods_id, 1, GoodsVipExp) of
                {_,  GoodPerExp} ->
                    lib_goods_api:cost_object_list(PlayerStatus, [{?TYPE_GOODS, GoodsInfo#goods.goods_id, GoodsNum}], goods_use, ""),
                    AddVipExp = round(GoodPerExp*UseNum),
                    NewPlayerStatus = lib_vip:calc_vip_status(PlayerStatus, AddVipExp),
                    {ok, NewPlayerStatus, UseNum};
                _ ->
                    {fail, ?ERRCODE(missing_config)}
            end;
        true ->
            {fail, ?ERRCODE(goods_not_enough)}
    end.

active_trial_vip(Player, GoodsInfo, GoodsNum) ->
    if GoodsInfo#goods.num >= GoodsNum andalso GoodsNum =/= 0 ->
            do_active_trial_vip(Player, GoodsInfo, GoodsNum);
        true ->
            if GoodsInfo#goods.num < GoodsNum ->
                    {fail, ?ERRCODE(goods_not_enough)};
                true ->
                    {fail, ?ERRCODE(data_error)}
            end
    end.

do_active_trial_vip(Player, GoodsInfo, GoodsNum) ->
    #player_status{id = RoleId, vip_status = VipStatus} = Player,
    #vip_status{lv = OldVipLv, type = OldVipType, trial_lv = OldTrialLv} = VipStatus,
    CheckL = [
        {active_trial_vip_goods_cfg, GoodsInfo#goods.goods_id},
        {is_active_trial_check, OldVipType, OldVipLv},
        % {is_active_vip_lv_check, VipLv},
        {active_trial_vip_goods_num, GoodsNum}
    ],
    case check(CheckL) of
        true ->
            lib_goods_api:cost_object_list(Player, [{?TYPE_GOODS, GoodsInfo#goods.goods_id, GoodsNum}], goods_use, ""),
            {TrialLv, TrialTime} = get_trial_goods(GoodsInfo#goods.goods_id),
            Now = utime:unixtime(),
            EndTime = Now + TrialTime,
            RestTime = EndTime rem 60,
            if RestTime == 0 ->
                    EndTime1 = EndTime;
                true ->
                    EndTime1 = EndTime + (60 - RestTime)
            end,
            NewVipStatus  = VipStatus#vip_status{trial_lv = TrialLv, type = ?VIP_TRIAL, endtime = EndTime1},
            NewVipStatus1 = lib_vip:set_time_out_caller_do(RoleId, NewVipStatus),
            if NewVipStatus1 =/= VipStatus -> db_update_vip(RoleId, NewVipStatus1);
                true -> skip
            end,
            NewPlayer0  = Player#player_status{vip_status = NewVipStatus1},
            {ok, NewPlayer1}  = lib_player_event:dispatch(NewPlayer0, ?EVENT_VIP, {OldVipLv, OldVipType, OldTrialLv}),
            lib_vip:send_vip_info(NewPlayer1),
            %% 日志
            lib_log_api:log_vip_status(RoleId, ?VIP_TRIAL, NewVipStatus1#vip_status.trial_lv, NewVipStatus1#vip_status.lv, GoodsInfo#goods.goods_id, ?VIP_LOG_0, NewVipStatus1#vip_status.endtime, Now),
            {ok, NewPlayer1, GoodsNum};
        {false, ErrCode} ->
            TrialCode = ?ERRCODE(err450_trial_vip_1),
            LvCode    = ?ERRCODE(err450_in_vip),
            lib_goods_api:cost_object_list(Player, [{?TYPE_GOODS, GoodsInfo#goods.goods_id, GoodsNum}], goods_use, ""),
            if (TrialCode == ErrCode orelse LvCode == ErrCode)
             andalso GoodsInfo#goods.goods_id == ?GOODS_ID_VIP_TRIAL_SP ->
                {use_sp_vip_goods, Player, GoodsNum};
                true ->
                    {ok, Player, GoodsNum}
            end
    end.

get_trial_goods(GoodsId) ->
    TrialGoodsCfg = data_vip:get_cfg(2),
    {_, TrialLv, TrialTime} = lists:keyfind(GoodsId, 1, TrialGoodsCfg),
    {TrialLv, TrialTime}.

%% ---------- 合法性检查 ------------

check_buy_privilege(RoleId, VipLv, VipStatus) ->
    #vip_status{lv = RoleVip, type = Type} = VipStatus,
    CheckL = [
        {is_vip_trial, Type},
        {vip_limit, VipLv, RoleVip},
        {is_buyed, RoleId, VipLv, RoleVip},
        {vip_gift_cfg, VipLv}
    ],
    case check(CheckL) of
        true ->
            #base_vip_gift{gift_reward = Rewards, cur_type = CurType, cur_price = Price} = data_vip:get_vip_gift(VipLv),
            {true, [{CurType, 0, Price}], Rewards};
        {false, ErrCode} ->
            {false, ErrCode}
    end.

check_active_sup_vip(_RoleId, Type, VipStatus) ->
    #vip_status{lv = VipLv, sup_vip = RoleSupVip} = VipStatus,
    #role_sup_vip{type = SupType, end_time = EndTime} = RoleSupVip,
    CheckL = [
        {active_trial_sup_vip, Type, VipLv},
        {check_sup_vip_type, SupType, EndTime, Type}
        % {trial_sup_vip_exist, Type, SupType, EndTime}
    ],
    case check(CheckL) of
        true ->
            % if Type == 0 ->
            ActiveCost = data_sup_vip:get_kv(trial_sup_vip_active),
            CostType   = active_trial_sup_vip,
            %     true ->
            %         ActiveCost = data_sup_vip:get_kv(total_charge),
            %         CostType   = active_sup_vip
            % end,
            {true, ActiveCost, CostType};
        {false, ErrCode} ->
            {false, ErrCode}
    end.

check_sup_vip_exchange(Type, GoodsId, ExchangeCount, Player) ->
    #player_status{id = RoleId, vip_status = RoleVip} = Player,
    #vip_status{lv = VipLv, sup_vip = RoleSupVip} = RoleVip,
    #role_sup_vip{type = SupVipType, last_reward_rec = LastRewardRec} = RoleSupVip,
    if Type == ?SUP_VIP_GIFT_EXCHANGE andalso LastRewardRec =/= 0 -> %% 每日礼包领取
            if SupVipType == ?PER_SUP_VIP ->
                    GiftCount = lib_daily:get_count(RoleId, ?MOD_SUP_VIP, ?SUP_VIP_DAILY_EXCHANGE, Type),
                    ConfigCount = data_sup_vip:get_kv(sup_vip_gift_count),
                    if GiftCount >= ConfigCount ->
                            {false, ?ERRCODE(err451_sup_vip_count_limit)};
                        true ->
                            SupVipGift = data_sup_vip:get_kv(daily_sup_vip_gift),
                            {true, [], SupVipGift, [], GiftCount}
                    end;
                SupVipType == ?TRIAL_SUP_VIP ->
                    GiftCount = lib_daily:get_count(RoleId, ?MOD_SUP_VIP, ?SUP_VIP_DAILY_EXCHANGE, Type),
                    ConfigCount = data_sup_vip:get_kv(trial_sup_vip_gift_count),
                    if GiftCount >= ConfigCount ->
                            {false, ?ERRCODE(err451_sup_vip_count_limit)};
                        true ->
                            SupVipGift = data_sup_vip:get_kv(daily_sup_vip_gift),
                            {true, [], SupVipGift, [], GiftCount}
                    end;
                true -> {false, ?ERRCODE(err451_no_sup_vip)}
            end;
        Type == ?SUP_VIP_GOLD_EXCHANGE -> %% 彩钻兑换
            GoldExchange = data_sup_vip:get_kv(gold_exchange),
            TrialGoldExchange = data_sup_vip:get_kv(trial_gold_exchange),
            if GoldExchange == [] orelse TrialGoldExchange ->
                    {false, ?MISSING_CONFIG};
                SupVipType =/= ?PER_SUP_VIP andalso SupVipType =/= ?TRIAL_SUP_VIP ->
                    {false, ?ERRCODE(err451_echange_arg_error)};
                true ->
                    ExchangeUseCount = lib_daily:get_count(RoleId, ?MOD_SUP_VIP, ?SUP_VIP_DAILY_EXCHANGE, Type),
                    if 
                        SupVipType == ?PER_SUP_VIP ->
                            ConfigCount = lib_sup_vip:calc_gold_exchange(VipLv, GoldExchange),
                            NewExchangeUseCount = ExchangeUseCount + ExchangeCount;
                        true ->
                            ConfigCount = lib_sup_vip:calc_gold_exchange(VipLv, TrialGoldExchange),
                            NewExchangeUseCount = ExchangeUseCount + ExchangeCount
                    end,
                    if  NewExchangeUseCount > ConfigCount orelse ExchangeCount == 0 ->
                            {false, ?ERRCODE(err451_exchange_count)};
                        true ->
                            case data_sup_vip:get_kv(gold_exchange_price) of
                                [{BGold, Gold}|_] ->
                                    {true, [{?TYPE_BGOLD, 0, round(BGold*ExchangeCount)}], [{?TYPE_GOLD, 0, round(Gold*ExchangeCount)}], [], ExchangeUseCount};
                                _ ->
                                    {false, ?MISSING_CONFIG}
                            end
                    end
            end;
        Type == ?SUP_VIP_FOSTER_GOODS_EXCHANGE -> %% 培养丹兑换
            if SupVipType == ?PER_SUP_VIP ->
                    ExchangeUseCount = lib_daily:get_count(RoleId, ?MOD_SUP_VIP, ?SUP_VIP_DAILY_EXCHANGE, Type),
                    ConfigExchangeCount = data_sup_vip:get_kv(foster_goods_exchange_count),
                    ConfigCount = lib_sup_vip:calc_goods_exchange(VipLv, ConfigExchangeCount),
                    case data_sup_vip:get_goods_count(GoodsId) of
                        [Cost = [_|_]|_] ->
                            NewExchangeUseCount = ExchangeUseCount + ExchangeCount,
                            if NewExchangeUseCount > ConfigCount orelse ExchangeCount == 0 ->
                                    {false, ?ERRCODE(err451_exchange_count)};
                                true ->
                                    Cost1 = [{PriceType, GoodsIdX, round(Num*ExchangeCount)} || {PriceType, GoodsIdX, Num} <- Cost],
                                    [{_, TotalNum}|_] = lib_goods_api:get_goods_num(Player, [GoodsId]),
                                    Result = lib_goods_api:check_object_list(Player, Cost1),
                                    if TotalNum >= ExchangeCount andalso Result == true ->
                                            NowTime = utime:unixtime(),
                                            GoodsStatus = lib_goods_do:get_goods_status(),
                                            AllGoodsList = lib_goods_util:get_type_goods_list_expire_time(RoleId, GoodsId, ?GOODS_LOC_BAG, NowTime, GoodsStatus#goods_status.dict),
                                            {SpiltGoods, NormalGoods} = lib_sup_vip:select_avaliable_goodslist(AllGoodsList, ExchangeCount),
                                            case SpiltGoods of
                                                [_|_] ->
                                                    case lib_sup_vip:check_spilt_null_cell(SpiltGoods, GoodsStatus) of
                                                        true ->
                                                            {true, Cost1, NormalGoods, SpiltGoods, ExchangeUseCount};
                                                        _ ->
                                                            {false, ?ERRCODE(err150_no_cell)}
                                                    end;
                                                _ ->
                                                    {true, Cost1, NormalGoods, [], ExchangeUseCount}
                                            end;
                                        true ->
                                            if TotalNum < ExchangeCount ->
                                                    {false, ?ERRCODE(goods_not_enough)};
                                                true ->
                                                    {false, ?ERRCODE(gold_not_enough)}
                                            end
                                    end
                            end;
                        _ ->
                            {false, ?MISSING_CONFIG}
                    end;
                true ->
                    {false, ?ERRCODE(err451_no_sup_vip)}
            end;
        true ->
            {false, ?FAIL}
    end.


check([]) ->
    true;
check([Check|CheckList]) ->
    case do_check(Check) of
        true -> check(CheckList);
        {false, ErrCode} -> {false, ErrCode}
    end.


do_check({vip_gift_cfg, VipLv}) ->
    case data_vip:get_vip_gift(VipLv) of
        #base_vip_gift{} ->
            true;
        _ ->
            {false, ?ERRCODE(err450_cfg_error)}
    end;
do_check({is_buyed, RoleId, VipLv, RoleVip}) ->
    if RoleVip >= VipLv andalso VipLv =/= 0 ->
            VipCount = lib_counter:get_count(RoleId, ?MOD_VIP, ?MOD_VIP_PRESENT, VipLv),
            % ?INFO_TTY("~p", [VipCount]),
            if VipCount =/= 0 ->
                    {false, ?ERRCODE(err450_have_buy_vip_bag)};
                true ->
                    true
            end;
        true ->
            {false, ?ERRCODE(err450_vip_limit)}
    end;
do_check({vip_limit, VipLv, RoleVip}) ->
    if RoleVip >= VipLv andalso VipLv =/= 0 ->
            true;
        true ->
            {false, ?ERRCODE(err450_vip_limit)}
    end;
do_check({is_vip_trial, Type}) ->
    if Type == ?VIP_TRIAL ->
            {false, ?ERRCODE(err450_trial_vip)};
        true ->
            true
    end;
do_check({is_active_trial_check, Type, Lv}) ->
    if Type == ?VIP_TRIAL ->
            {false, ?ERRCODE(err450_trial_vip_1)};
        true ->
            if Lv == 0 ->
                    true;
                true -> %% Lv =/= 0 andalso Type == ?VIP_NORMAL
                    {false, ?ERRCODE(err450_in_vip)}
            end
    end;
do_check({is_active_vip_lv_check, VipLv}) ->
    if VipLv =/= 0 ->
            {false, ?ERRCODE(err450_in_vip)};
        true ->
            true
    end;
do_check({active_trial_vip_goods_num, GoodsNum}) ->
    if GoodsNum == 1 ->
            true;
        true ->
            {false, ?ERRCODE(err450_goods_num)}
    end;
do_check({vip_use_limit, GoodsId, VipType, _Lv}) ->
    if VipType == ?VIP_TRIAL ->
            {false, ?ERRCODE(err450_trial_vip)};
        true ->
            case data_goods_effect:get(GoodsId) of
                #goods_effect{effect_list = [{fosters_up, _FosterCell, _DownGrade, _UpGrade}|_]} ->
                    true;
                _ ->
                    {false, ?ERRCODE(err154_missing_config)}
            end
    end;
do_check({active_trial_vip_goods_cfg, GoodsId}) ->
    TrialGoods = data_vip:get_cfg(2),
    case lists:keyfind(GoodsId, 1, TrialGoods) of
        {_, _TrialLv, _TrialTime} ->
            true;
        _ ->
            {false, ?ERRCODE(err154_missing_config)}
    end;
do_check({active_trial_sup_vip, Type, VipLv}) ->
    if Type == 0 ->
            SupVipLimit = data_sup_vip:get_kv(trial_sup_vip_lv_limit),
            if VipLv < SupVipLimit ->
                    {false, ?ERRCODE(err451_sup_vip_active_limit)};
                true ->
                    true
            end;
        true ->
            {false, ?FAIL}
    end;
do_check({check_sup_vip_type, SupType, _EndTime, Type}) ->
    if Type == 0 ->
            if SupType >= ?TRIAL_SUP_VIP ->
                    {false, ?ERRCODE(err451_actived_sup_vip)};
                true -> true
            end;
        true ->
            {false, ?FAIL}
    end;
do_check({trial_sup_vip_exist, _Type, _SupVipType, EndTime}) ->
    if EndTime == 0 ->
            true;
        true ->
            Now = utime:unixtime(),
            if Now < EndTime ->
                    {false, ?ERRCODE(err451_in_trial_sup_vip)};
                true ->
                    true
            end
    end;
do_check({is_sup_vip, SupVipType, _EndTime}) ->
    if SupVipType >= ?TRIAL_SUP_VIP ->
            true;
        true ->
            {false, ?ERRCODE(err451_no_sup_vip)}
    end;
do_check({is_permanent_sup_vip, SupVipType}) ->
    if SupVipType == ?PER_SUP_VIP ->
            true;
        true ->
            {false, ?ERRCODE(err451_permanent_sup_vip)}
    end;
do_check({unlock_goods_check, GoodsId, UnlockIds}) ->
    case data_sup_vip:get_goods(GoodsId) of
        #base_sup_vip_store{type = Type, index = Index} ->
            if Type == ?SUP_VIP_SOTRE_DEFAULT ->
                    true;
                true ->
                    if UnlockIds == [] ->
                            {false, ?ERRCODE(err451_unlock_limit)};
                        true ->
                            MaxUnlockId = lists:max(UnlockIds),
                            MaxCanUnlock = MaxUnlockId+1,
                            if Index > MaxCanUnlock ->
                                    {false, ?ERRCODE(err451_unlock_limit)};
                                true ->
                                    true
                            end
                    end
            end;
        _ ->
            {false, ?ERRCODE(missing_config)}
    end;
do_check({goods_limit_check, RoleId, RoleLv, GoodsId, GoodsNum, _UnlockIds}) ->
    case data_sup_vip:get_goods(GoodsId) of
        #base_sup_vip_store{limit_buy = Limits, lv = ConfigLvs} ->
            CheckLvResult =
             if ConfigLvs == [] -> true;
                true ->
                    [MinLv, MaxLv|_] = ConfigLvs,
                    RoleLv >= MinLv andalso RoleLv =< MaxLv
            end,
            case CheckLvResult of
                true ->
                    if Limits == [] ->
                            true;
                        true ->
                            [{LimitType, ConfigLimitCount}|_] = Limits,
                            if LimitType == ?SUP_VIP_LIMIT_DAILY ->
                                    DailyCount = lib_daily:get_count(RoleId, ?MOD_SUP_VIP, ?SUP_VIP_DAILY_BUY_LIMIT, GoodsId),
                                    NewCount   = DailyCount + GoodsNum;
                                LimitType == ?SUP_VIP_LIMIT_WEEK ->
                                    WeekCount = lib_week:get_count(RoleId, ?MOD_SUP_VIP, ?SUP_VIP_WEEK_BUY_LIMIT, GoodsId),
                                    NewCount  = WeekCount + GoodsNum;
                                LimitType == ?SUP_VIP_LIMIT_PERMANENT ->
                                    PerCount = lib_counter:get_count(RoleId, ?MOD_SUP_VIP, ?SUP_VIP_PER_BUY_LIMIT, GoodsId),
                                    NewCount = PerCount + GoodsNum;
                                true ->
                                    NewCount = 0
                            end,
                            if NewCount > ConfigLimitCount ->
                                    {false, ?ERRCODE(err451_limit_count_error)};
                                true ->
                                    true
                            end
                    end;
                _ ->
                    {false, ?ERRCODE(err451_goods_lv_limit)}
            end;
        _ ->
            {false, ?ERRCODE(missing_config)}
    end;
do_check({goods_price_check, GoodsId}) ->
    case data_sup_vip:get_goods(GoodsId) of
        #base_sup_vip_store{price = [_|_]} ->
            true;
        _ ->
            {false, ?ERRCODE(missing_config)}
    end;
do_check(CheckMsg) ->
    ?ERR("bad match do_check:~p~n",[CheckMsg]),
    {false, ?FAIL}.


%% ---------------------------------

get_vip_lv_db(RoleId) ->
    case db:get_row(?SELECT_ROLE_VIP_LV, [RoleId]) of
        [Lv|_] ->
            Lv;
        _ ->
            0
    end.

db_select_vip(RoleId) ->
    case db:get_row(?SELECT_ROLE_VIP, [RoleId]) of
        [Lv, RealLv, Exp, Type, EndTime|_] ->
            #vip_status{trial_lv = Lv, lv = RealLv, exp = Exp, type = Type, endtime = EndTime};
        _ ->
            #vip_status{}
    end.

db_update_vip(RoleId, VipStatus) ->
    #vip_status{
        trial_lv = Lv, lv = RealLv, exp = Exp, type = Type, endtime = EndTime
    } = VipStatus,
    db:execute(?REPLACE_ROLE_VIP, [RoleId, Lv, RealLv, Exp, Type, EndTime]),
    ok.

%% -------------------------------------

gm_reset_vip(Val, Player) ->
    #player_status{id = RoleId, vip_status = VipStatus, figure = #figure{name = RoleName}} = Player,
    lib_player_record:role_func_check_delete(RoleId, ?FUNC_TYPE_VIP),
    case data_vip:get_vip(Val) of
        #base_vip_cfg{} -> NewVal = Val;
        _ -> NewVal = 0
    end,
    NewVipStatus = VipStatus#vip_status{
        trial_lv = 0, lv = NewVal, type = 0, exp = 0,
        endtime = 0
    },
    db_update_vip(RoleId, NewVipStatus),
    NewPlayer = Player#player_status{vip_status = NewVipStatus},
    VipLvs = data_vip:get_all_vip_lv(),
    VipLvs1 = [{{?MOD_VIP, ?MOD_VIP_PRESENT, X}, 0} || X <- VipLvs],
    lib_counter:set_count(RoleId, VipLvs1),
    % db:execute(<<"DELETE FROM counter WHERE role_id = ~p and module = ~p and sub_module = ~p">>, [RoleId, ?MOD_VIP, ?MOD_VIP_PRESENT]),
    NewPlayer1 = lib_vip:set_new_vip_figure(NewPlayer),
    lib_vip:send_vip_info(NewPlayer1),
    pp_vip:handle(NewPlayer1, 45005, []),
    case data_vip:get_vip(Val) of
        #base_vip_cfg{name = Name} ->
            lib_chat:send_TV({all}, ?MOD_VIP, 1, [RoleName, RoleId, Name]);
        _ ->
            skip
    end,
    NewPlayer1.