%% ---------------------------------
%% desc     :贵族功能逻辑
%% module   :lib_sup_vip
%% author   :hh
%% time     :20/04/13
%% ---------------------------------

-module(lib_sup_vip).

-export([
    login/1,
    sup_vip_time_out/2,
    db_update_role_sup_vip/2,
    active_trial_sup_vip/1,
    % active_sup_vip/1,
    exchange_info/2,
    expire_goods_exchange/7,
    bgold_to_gold/5,
    get_store_info/3,
    sup_vip_buy/3,
    get_sup_vip_on_db/1,
    get_sup_vip_skill/1,
    calc_gold_exchange/2,
    calc_goods_exchange/2,
    check_spilt_null_cell/2,
    select_avaliable_goodslist/2,

    is_sup_vip/1,
    is_per_sup_sip/1,
    sup_vip_type/1,

    get_lock_ids/0,
    get_day/1,
    get_sup_vip_star/1,
    login_rewards_status/1,
    get_login_rewards/3
    ]).

-export([
    cost_star/4,
    is_enough_star/2,
    calc_power/3
    ]).

-export([
    handle_event/2,
    send_sup_vip_info/1,
    get_daily_data/8,
    get_weekly_data/8,
    get_permanent_data/8
    ]).

-export([gm_reset_supvip/1]).
-export([test/0]).
-export([calc_trial_sup_vip_end_time/0]).

-include("server.hrl").
-include("common.hrl").
-include("goods.hrl").
-include("vip.hrl").
-include("errcode.hrl").
-include("rec_event.hrl").
-include("def_event.hrl").
-include("def_module.hrl").
-include("def_goods.hrl").
-include("sql_goods.hrl").
-include("daily.hrl").
-include("figure.hrl").
-include("predefine.hrl").
-include("skill.hrl").

-define(TITLE,      utext:get(4510001)).
-define(CONTENT,    utext:get(4510002)).

%% 登录
login(RoleId) ->
    case db:get_row(?SELECT_ROLE_SUP_VIP, [RoleId]) of
        [Type, ContinueChargeDays, TodayCharge, LastTime, TotalCharge, EndTime, Unlocks, TodayStar, UpdateTime,
         LoginRewardsBin, LastRewardRec|_] ->
            RoleSupVip = #role_sup_vip{
                type = Type,
                continue_charge_days = ContinueChargeDays,
                today_charge = TodayCharge,
                last_time = LastTime,
                total_charge = TotalCharge,
                end_time = EndTime,
                unlock_ids = util:bitstring_to_term(Unlocks),
                today_star = TodayStar,
                update_time = UpdateTime,
                login_rewards = util:bitstring_to_term(LoginRewardsBin),
                last_reward_rec = LastRewardRec
            },
            RoleSupVip;
        _ ->
            #role_sup_vip{}
    end.

get_sup_vip_on_db(RoleId) ->
    case db:get_row(?SELECT_ROLE_SUP_VIP_TYPE, [RoleId]) of
        [Type, EndTime|_] ->
            if Type == ?PER_SUP_VIP ->
                    Type;
                Type == ?TRIAL_SUP_VIP ->
                    Now = utime:unixtime(),
                    if Now < EndTime ->
                            Type;
                        true ->
                            ?NO_SUP_VIP
                    end;
                true ->
                    ?NO_SUP_VIP
            end;
        _ ->
            ?NO_SUP_VIP
    end.

db_update_role_sup_vip(RoleId, RoleSupVip) ->
    #role_sup_vip{
        type = Type,
        continue_charge_days = ContinueChargeDays,
        today_charge = TodayCharge,
        last_time = LastTime,
        total_charge = TotalCharge,
        end_time = EndTime,
        unlock_ids = Unlocks,
        today_star = TodayStar,
        update_time = UpdateTime,
        login_rewards = LoginRewards,
        last_reward_rec = LastTimeRec
    } = RoleSupVip,
    UnLockBin = util:term_to_bitstring(Unlocks),
    LoginRewardsBin = util:term_to_bitstring(LoginRewards),
    db:execute(?REPLACE_ROLE_SUP_VIP, 
        [RoleId, Type, ContinueChargeDays, TodayCharge, LastTime, TotalCharge, EndTime, UnLockBin, TodayStar, UpdateTime,
         LoginRewardsBin, LastTimeRec]),
    ok.

handle_event(Player, #event_callback{type_id = ?EVENT_RECHARGE, data = #callback_recharge_data{gold = Gold, money = Money}}) ->
    NewPlayer = calc_sup_vip_status(Player, Gold),
    NewPlayer1 = add_star(NewPlayer, Money),
    {ok, NewPlayer1};
handle_event(Player, #event_callback{type_id = ?EVENT_LOGIN_CAST}) ->
    #player_status{id = RoleId, figure = Figure, vip_status = VipStatus} = Player,
    #vip_status{sup_vip = RoleSupVip} = VipStatus,
    Now = utime:unixtime(),
    RoleSupVip1 = update_sup_vip_login_data(RoleId, RoleSupVip, Now),
    SupVipType = sup_vip_type(RoleSupVip1),
    NewFigure = Figure#figure{sup_vip = SupVipType},
    NewPlayer = Player#player_status{figure = NewFigure, vip_status = VipStatus#vip_status{sup_vip = RoleSupVip1}},
    lib_role:update_role_show(RoleId, [{sup_vip, SupVipType}]),
    {ok, NewPlayer};
handle_event(Player, #event_callback{type_id = ?EVENT_ZERO_CLOCK}) ->
    #player_status{id = RoleId, sid = Sid, vip_status = #vip_status{sup_vip = RoleSupVip} = VipStatus} = Player,
    SupVipType = sup_vip_type(VipStatus#vip_status.sup_vip),
    NowTime = utime:unixtime(),
    RoleSupVip1 = update_sup_vip_login_data(RoleId, RoleSupVip, NowTime),
    VipStatus1 = VipStatus#vip_status{sup_vip = RoleSupVip1},

    BinData = lists:foldl(fun(Type, Acc) ->
        RestCount = get_rest_count(Type, RoleId, SupVipType, VipStatus#vip_status.lv),
        {ok, Bin} = pt_451:write(45107, [Type, RestCount]),
        <<Bin/binary, Acc/binary>>
    end, <<>>, [?SUP_VIP_GIFT_EXCHANGE, ?SUP_VIP_GOLD_EXCHANGE, ?SUP_VIP_FOSTER_GOODS_EXCHANGE]),
    case RoleSupVip of
        #role_sup_vip{end_time = EndTime, today_charge = TodayCharge, total_charge = TotalCharge, continue_charge_days = ContinueDay} ->
            GiftCount = lib_daily:get_count(RoleId, ?MOD_SUP_VIP, ?SUP_VIP_DAILY_EXCHANGE, ?SUP_VIP_GIFT_EXCHANGE);
        _ ->
            SupVipType = ?NO_SUP_VIP, EndTime = 0, TodayCharge = 0, TotalCharge = 0, ContinueDay = 0, GiftCount = 0
    end,
    {ok, BinData1} = pt_451:write(45101, [SupVipType, EndTime, TodayCharge, TotalCharge, ContinueDay, 0, GiftCount]),
    {ok, BinData2} = pt_451:write(45106, [?SUCCESS, 0]),
    lib_server_send:send_to_sid(Sid, <<BinData/binary, BinData1/binary, BinData2/binary>>),
    
    {ok, Player#player_status{vip_status = VipStatus1}};
handle_event(Player, #event_callback{type_id = ?EVENT_SUP_VIP_CHANGE}) ->
    %% 触发成就
    lib_role_visus:handle_spec_skill_achievement(Player),
    {ok, Player};
handle_event(Player, _) ->
    {ok, Player}.

calc_power(Player, _AttrPower, _BaseAttr) ->
    case get_sup_vip_skill(Player) of
        [{SkillId, Lv}|_] ->
            case data_skill:get(SkillId, Lv) of
                #skill{lv_data = #skill_lv{power = SkillPower}} ->
                    {Player, SkillPower};
                _ ->
                    {Player, 0}
            end;
        _ ->
            {Player, 0}
    end.

calc_sup_vip_status(Player, Gold) ->
    #player_status{id = RoleId, sid = Sid, vip_status = RoleVip, figure = Figure, passive_skills = Skills} = Player,
    #vip_status{lv = VipLv, sup_vip = RoleSupVip} = RoleVip,
    SupVipLimit = data_sup_vip:get_kv(trial_sup_vip_lv_limit),
    if VipLv >= SupVipLimit ->
            {UpdateFigure, NewRoleSupVip} = do_calc_sup_vip_status(RoleId, Figure#figure.name, RoleSupVip, Gold),
            NewRoleVip = RoleVip#vip_status{sup_vip = NewRoleSupVip},
            if UpdateFigure == true ->
                    %% 更新外观数据
                    NewFigure = Figure#figure{sup_vip = ?PER_SUP_VIP},
                    lib_role:update_role_show(RoleId, [{sup_vip, ?PER_SUP_VIP}]),
                    %% 更新禁跳技能数据
                    NewSkills = update_sup_vip_skill(Skills),
                    ValueList = [{passive_skill, get_sup_vip_skill()}],
                    mod_scene_agent:update(Player, ValueList),
                    NewPlayer = Player#player_status{vip_status = NewRoleVip, figure = NewFigure, passive_skills = NewSkills},
                    #role_sup_vip{type = SupVipType, end_time = EndTime, today_charge = TodayCharge, total_charge = TotalCharge, continue_charge_days = ContinueDay} = NewRoleSupVip,
                    GiftCount = lib_daily:get_count(RoleId, ?MOD_SUP_VIP, ?SUP_VIP_DAILY_EXCHANGE, ?SUP_VIP_GIFT_EXCHANGE),
                    lib_server_send:send_to_sid(Sid, pt_451, 45101, [SupVipType, EndTime, TodayCharge, TotalCharge, ContinueDay, 0, GiftCount]),
                    lib_skill:send_my_skill_list(NewPlayer),
                    OldSupVipType = RoleSupVip#role_sup_vip.type,
                    {ok, NewPlayer1} = lib_player_event:dispatch(NewPlayer, ?EVENT_SUP_VIP_CHANGE, [OldSupVipType]),
                    NewPlayer1;
                true ->
                    Player#player_status{vip_status = NewRoleVip}
            end;
        true ->
            Player
    end.

update_sup_vip_skill(Skills) ->
    case lists:keyfind(?SUPVIP_FORBID_JUMP_SKILL, 1, Skills) of
        {_, _} -> Skills;
        _      ->
            [{?SUPVIP_FORBID_JUMP_SKILL, 1}] ++ Skills
    end.

do_calc_sup_vip_status(RoleId, RoleName, RoleSupVip, Gold) ->
    #role_sup_vip{
        type = SupVipType, continue_charge_days = ContinueChargeDays, today_charge = TodayCharge,
        last_time = LastTime, total_charge = TotalCharge} = RoleSupVip,
    Now = utime:unixtime(),
    NewTotalRecharge = round(TotalCharge+Gold),
    [{_, _, ConfigTotalRecharge}|_] = data_sup_vip:get_kv(total_charge),
    SupVipType == ?TRIAL_SUP_VIP andalso lib_log_api:log_trial_sup_vip_charge(RoleId, Gold, NewTotalRecharge, Now),
    if SupVipType == ?PER_SUP_VIP orelse SupVipType == ?NO_SUP_VIP -> %% 永久贵族或体验贵族身份
            {false, RoleSupVip};
        % EndTime == 0 -> 非贵族身份 SupVipType == ?NO_SUP_VIP orelse
        %     {false, RoleSupVip};
        NewTotalRecharge >= ConfigTotalRecharge ->
            %% 变成永久
            NewRoleSupVip = change_sup_vip(permanent, RoleId, NewTotalRecharge, RoleSupVip),
            %% 日志
            lib_log_api:log_sup_vip_status(RoleId, NewRoleSupVip#role_sup_vip.type, ?SUP_VIP_LOG_1, Now),
            lib_chat:send_TV({all}, ?MOD_SUP_VIP, 2, [RoleName, RoleId]),
            {true, NewRoleSupVip};
        true ->
            % if EndTime > Now -> %% 体验阶段检测连续充值事件
                    {NewTodayCharge, NewContinueChargeDays} = update_continue_day(ContinueChargeDays, TodayCharge, Now, LastTime, Gold),
                    ConfigContinueDay = data_sup_vip:get_kv(continue_day),
                    if NewContinueChargeDays >= ConfigContinueDay ->
                            NewRoleSupVip = change_sup_vip(permanent, RoleId, NewTotalRecharge, RoleSupVip),
                            lib_chat:send_TV({all}, ?MOD_SUP_VIP, 2, [RoleName, RoleId]),
                            %% 日志
                            lib_log_api:log_sup_vip_status(RoleId, NewRoleSupVip#role_sup_vip.type, ?SUP_VIP_LOG_2, Now),
                            {true, NewRoleSupVip};
                        true ->
                            NewRoleSupVip = RoleSupVip#role_sup_vip{
                                last_time = Now, total_charge = NewTotalRecharge, continue_charge_days = NewContinueChargeDays,
                                today_charge = NewTodayCharge},
                            db_update_role_sup_vip(RoleId, NewRoleSupVip),
                            {false, NewRoleSupVip}
                    end
            %     true -> %% 体验过期只记录累充
            %         NewRoleSupVip = RoleSupVip#role_sup_vip{last_time = Now, total_charge = NewTotalRecharge},
            %         db_update_role_sup_vip(RoleId, NewRoleSupVip),
            %         {false, NewRoleSupVip}
            % end
    end.

%% 更新连续充值状态,只需达到累计天数即可
update_continue_day(ContinueChargeDays, TodayCharge, Now, LastTime, Gold) ->
   DiffDay = utime:day_span(Now, LastTime),
   ConfigTodayCharge = data_sup_vip:get_kv(continue_day_charge),
   case DiffDay of
        1 -> %% 同一天
            NewTodayCharge = round(TodayCharge+Gold),
            if TodayCharge < ConfigTodayCharge andalso NewTodayCharge >= ConfigTodayCharge ->
                    {NewTodayCharge, ContinueChargeDays+1};
                true ->
                    {NewTodayCharge, ContinueChargeDays}
            end;
        _ -> %% 不是同一天
            NewTodayCharge = Gold,
            if NewTodayCharge >= ConfigTodayCharge ->
                    {NewTodayCharge, ContinueChargeDays+1};
                true ->
                    {NewTodayCharge, ContinueChargeDays}
            end
        % _ -> %% 不是相邻两天
        %     NewTodayCharge = Gold,
        %     if NewTodayCharge >= ConfigTodayCharge ->
        %             {NewTodayCharge, 1};
        %         true ->
        %             {NewTodayCharge, 0}
        %     end
    end.

%% 变成永久贵族
change_sup_vip(permanent, RoleId, TotalCharge, RoleSupVip) ->
    NewRoleSupVip = RoleSupVip#role_sup_vip{
        type = ?PER_SUP_VIP, continue_charge_days = 0, today_charge = 0, total_charge = TotalCharge},
    db_update_role_sup_vip(RoleId, NewRoleSupVip),
    NewRoleSupVip;
change_sup_vip(_, _, _, RoleSupVip) ->
    RoleSupVip.

%% 激活体验贵族
active_trial_sup_vip(Player) ->
    #player_status{id = RoleId, figure = Figure = #figure{name = RoleName}, vip_status = VipStatus} = Player,
    #vip_status{sup_vip = RoleSupVip} = VipStatus,
    NowTime = utime:unixtime(),
    DailyCharge   = lib_recharge_api:get_today_pay_gold(RoleId),
    {_, ContinueChargeDays} = update_continue_day(0, 0, NowTime, 0, DailyCharge),
    NewRoleSupVip = RoleSupVip#role_sup_vip{
        type = ?TRIAL_SUP_VIP, continue_charge_days = ContinueChargeDays, last_time = NowTime, today_charge = DailyCharge,
        login_rewards = [{1, 0, 0}]},
    db_update_role_sup_vip(RoleId, NewRoleSupVip),
    NewVipStatus = VipStatus#vip_status{sup_vip = NewRoleSupVip},
    NewPlayer = Player#player_status{vip_status = NewVipStatus},

    %% 传闻
    lib_chat:send_TV({all}, ?MOD_SUP_VIP, 1, [RoleName, RoleId]),

    lib_role:update_role_show(RoleId, [{sup_vip, ?TRIAL_SUP_VIP}]),
    NewFigure = Figure#figure{sup_vip = ?TRIAL_SUP_VIP},
    NewPlayer1 = NewPlayer#player_status{figure = NewFigure},

    OldSupVipType = ?NO_SUP_VIP,
    {ok, NewPlayer2} = lib_player_event:dispatch(NewPlayer1, ?EVENT_SUP_VIP_CHANGE, [OldSupVipType]),

    %%
    SupVipSkills = get_sup_vip_skill(NewPlayer2),
    ValueList = [{passive_skill, SupVipSkills}],
    mod_scene_agent:update(NewPlayer2, ValueList),
    NewPlayer3 = lib_player:count_player_attribute(NewPlayer2, ?MOD_SUP_VIP, active_trial_sup_vip),
    lib_player:send_attribute_change_notify(NewPlayer3, ?NOTIFY_ATTR),
    lib_skill:send_my_skill_list(NewPlayer3),
    %% 日志
    lib_log_api:log_sup_vip_status(RoleId, ?TRIAL_SUP_VIP, ?SUP_VIP_LOG_0, NowTime),

    NewPlayer3.

%% 体验贵族过期
sup_vip_time_out(Player, _) -> Player.

%% 兑换信息
exchange_info(Type, Player) ->
    #player_status{id = RoleId, sid = Sid, vip_status = VipStatus} = Player,
    case VipStatus#vip_status.sup_vip of
        RoleSupVip = #role_sup_vip{} -> ok;
        _ -> RoleSupVip = #role_sup_vip{}
    end,
    #role_sup_vip{type = SupVipType} = RoleSupVip,
    RestCount = get_rest_count(Type, RoleId, SupVipType, VipStatus#vip_status.lv),
    % ?ERR("~p ~p", [Type, RestCount]),
    lib_server_send:send_to_sid(Sid, pt_451, 45107, [Type, RestCount]),
    ok.

get_rest_count(Type, RoleId, SupVipType, VipLv) ->
    if Type == ?SUP_VIP_GIFT_EXCHANGE ->
            Count = lib_daily:get_count(RoleId, ?MOD_SUP_VIP, ?SUP_VIP_DAILY_EXCHANGE, Type),
            if SupVipType == ?TRIAL_SUP_VIP ->
                    ConfigCount = data_sup_vip:get_kv(trial_sup_vip_gift_count);
                SupVipType == ?PER_SUP_VIP ->
                    ConfigCount = data_sup_vip:get_kv(sup_vip_gift_count);
                true ->
                    ConfigCount = 0
            end,
            RestCount = max(0, ConfigCount - Count);
        Type == ?SUP_VIP_GOLD_EXCHANGE ->
            if SupVipType == ?PER_SUP_VIP orelse SupVipType == ?TRIAL_SUP_VIP ->
                    Count = lib_daily:get_count(RoleId, ?MOD_SUP_VIP, ?SUP_VIP_DAILY_EXCHANGE, Type),
                    if SupVipType == ?PER_SUP_VIP ->
                            GoldExchange = data_sup_vip:get_kv(gold_exchange);
                        true ->
                            GoldExchange = data_sup_vip:get_kv(trial_gold_exchange)
                    end,
                    ConfigCount = calc_gold_exchange(VipLv, GoldExchange),
                    RestCount = max(0, ConfigCount - Count);
                true ->
                    RestCount = 0
            end;
        Type == ?SUP_VIP_FOSTER_GOODS_EXCHANGE ->
            if SupVipType == ?PER_SUP_VIP ->
                    Count = lib_daily:get_count(RoleId, ?MOD_SUP_VIP, ?SUP_VIP_DAILY_EXCHANGE, Type),
                    GoodsExchange = data_sup_vip:get_kv(foster_goods_exchange_count),
                    ConfigCount = calc_goods_exchange(VipLv, GoodsExchange),
                    RestCount = max(0, ConfigCount - Count);
                true ->
                    RestCount = 0
            end;
        true ->
            RestCount = 0
    end,
    RestCount.

%% 彩钻兑换
bgold_to_gold(Player, Cost, Rewards, OldCount, ExchangeNum) ->
    #player_status{id = RoleId, sid = Sid, figure = #figure{name = RoleName, vip = VipLv}, pid = Pid, bgold = BGold} = Player,
    [{_, _, CostNum}|_] = Cost,
    ConsumeType = gold_exchange_cost,
    NewPlayer = Player#player_status{bgold = round(BGold - CostNum)},
    lib_player:update_player_money(Player, NewPlayer),
    lib_player:send_attribute_change_notify(NewPlayer, ?NOTIFY_MONEY),
    lib_consume_data:update_money_consume(NewPlayer, Player, ConsumeType),
    lib_player_event:async_dispatch(Pid, ?EVENT_MONEY_CONSUME,
        #callback_money_cost{consume_type = ConsumeType, money_type = ?TYPE_BGOLD, cost = CostNum, args = #{old_bgold => BGold}}),
    NewPlayer1 = lib_goods_api:send_reward(NewPlayer, Rewards, gold_exchange_rewards),
    lib_daily:plus_count(RoleId, ?MOD_SUP_VIP, ?SUP_VIP_DAILY_EXCHANGE, ?SUP_VIP_GOLD_EXCHANGE, ExchangeNum),
    lib_server_send:send_to_sid(Sid, pt_451, 45103, [?SUCCESS, ?SUP_VIP_GOLD_EXCHANGE]),
    lib_log_api:log_sup_vip_exchange(RoleId, RoleName, VipLv, ?SUP_VIP_EXCHANGE_1, Cost, Rewards, OldCount, round(OldCount+ExchangeNum), Player#player_status.gold, NewPlayer#player_status.gold),
    NewPlayer1.

%% 限时丹兑换
expire_goods_exchange(Type, Cost, NormalGoods, SpiltGoods, OldCount, ExchangeCount, Player) ->
    #player_status{id = RoleId, sid = Sid, figure = #figure{name = RoleName, vip = VipLv}} = Player,
    case lib_goods_api:cost_object_list_with_check(Player, Cost, expire_goods_exchange_cost, "") of
        {true, NewPlayer,_} ->
            GoodsStatus = lib_goods_do:get_goods_status(),
            % AllGoodsList = lib_goods_util:get_type_goods_list_expire_time(RoleId, GoodsId, ?GOODS_LOC_BAG, NowTime, GoodsDict),
            % {SpiltGoods, NormalGoods} = select_avaliable_goodslist(AllGoodsList, ExchangeCount),
            case expire_goods_exchange_do(RoleId, {SpiltGoods, NormalGoods}, GoodsStatus, expire_goods_exchange) of
                true ->
                    lib_daily:plus_count(RoleId, ?MOD_SUP_VIP, ?SUP_VIP_DAILY_EXCHANGE, Type, ExchangeCount),
                    lib_server_send:send_to_sid(Sid, pt_451, 45103, [?SUCCESS, Type]),
                    Goods1 = [{?TYPE_GOODS, GoodsId, GoodsNum} || #goods{goods_id = GoodsId, num = GoodsNum} <- NormalGoods],
                    Goods2 = [{?TYPE_GOODS, GoodsIdX, NeedSpiltX} || {#goods{goods_id = GoodsIdX}, NeedSpiltX} <- SpiltGoods],
                    LogGoods = lib_goods_util:merge_same_goods(Goods1++Goods2),
                    LogCost = Cost ++ LogGoods,
                    RewardList = LogGoods,
                    lib_log_api:log_sup_vip_exchange(RoleId, RoleName, VipLv, ?SUP_VIP_EXCHANGE_2, LogCost, RewardList, OldCount, OldCount+ExchangeCount, Player#player_status.gold, NewPlayer#player_status.gold),
                    {ok, NewPlayer};
                _ ->
                    lib_server_send:send_to_sid(Sid, pt_451, 45103, [?FAIL, Type]),
                    ok
            end;
        {false, Errcode} ->
            lib_server_send:send_to_sid(Sid, pt_451, 45103, [Errcode, Type]),
            ok
    end.

select_avaliable_goodslist(AllGoodsList, ExchangeCount) ->
    SortedGoodsList = lists:keysort(#goods.expire_time, AllGoodsList),
    select_goodslist_do(SortedGoodsList, 0, ExchangeCount, {[], []}).
    % lists:sublist(SortedGoodsList, ExchangeCount).


select_goodslist_do([], _, _, {SpiltGoods, NormalGoods}) -> {SpiltGoods, NormalGoods};
select_goodslist_do([GoodsInfo|Rest], Acc, ExchangeCount, {SpiltGoods, NormalGoods}) ->
    NewAcc = GoodsInfo#goods.num + Acc,
    if NewAcc >= ExchangeCount ->
            if NewAcc == ExchangeCount ->
                    {SpiltGoods, [GoodsInfo|NormalGoods]};
                true ->
                    NeedSpiltNum = GoodsInfo#goods.num - (NewAcc - ExchangeCount),
                    {[{GoodsInfo, NeedSpiltNum}|SpiltGoods], NormalGoods}
            end;
        true ->
            select_goodslist_do(Rest, NewAcc, ExchangeCount, {SpiltGoods, [GoodsInfo|NormalGoods]})
    end.

expire_goods_exchange_do(RoleId, {SpiltGoods, NormalGoods}, GoodsStatus, Type) ->
    F = fun() ->
        ok = lib_goods_dict:start_dict(),
        {true, GoodsStatus1} = update_goods_expire_time(RoleId, NormalGoods, GoodsStatus),
        {true, GoodsStatus2} = update_goods_expire_time_and_spilt(RoleId, SpiltGoods, GoodsStatus1),
        {NewGoodsDict, UpdateGoodsList} = lib_goods_dict:handle_dict_and_notify(GoodsStatus2#goods_status.dict),
        {true, GoodsStatus2#goods_status{dict = NewGoodsDict}, UpdateGoodsList}
    end,
    case catch goods_transaction:transaction(F) of
        {true, NewGoodsStatus, UpdateGoodsList} ->
            lib_goods_do:set_goods_status(NewGoodsStatus),
            lib_goods_api:notify_client(RoleId, UpdateGoodsList, Type),
            true;
        _Error ->
            ?ERR("error happen ~w", [_Error]),
            false
    end.

update_goods_expire_time(_, [], GoodsStatus) -> {true, GoodsStatus};
update_goods_expire_time(RoleId, [GoodsInfo|Rest], GoodsStatus) ->
    NewGoodsInfo = GoodsInfo#goods{expire_time = 0},
    Sql = io_lib:format(?SQL_GOODS_UPDATE_EXPIRE, [0, NewGoodsInfo#goods.id, RoleId]),
    goods_transaction:add_sql(Sql),
    NewGoodsDict = lib_goods_dict:append_dict({add, goods, NewGoodsInfo}, GoodsStatus#goods_status.dict),
    update_goods_expire_time(RoleId, Rest, GoodsStatus#goods_status{dict = NewGoodsDict}).

%% 拆分道具数量并修改过期时间
update_goods_expire_time_and_spilt(_, [], GoodsStatus) -> {true, GoodsStatus};
update_goods_expire_time_and_spilt(RoleId, [{GoodsInfo, NeedSpilt}|Rest], GoodsStatus) ->
    NewNum = GoodsInfo#goods.num - NeedSpilt,
    [_, NewGoodsStatus] = goods_logic:change_goods_num(GoodsInfo, NewNum, GoodsStatus),
    NewGoodsInfo = GoodsInfo#goods{id = 0, num = NeedSpilt, expire_time = 0},
    [_, NewGoodsStatus1] = goods_logic:add_goods(NewGoodsInfo, NewGoodsStatus),
    update_goods_expire_time_and_spilt(RoleId, Rest, NewGoodsStatus1).

%% 检测拆分需要的格子是否满足
check_spilt_null_cell(SpiltGoods, GoodsStatus) ->
    NeedNullCell = calc_need_null_cell_num(SpiltGoods),
    HasNullCell  = lib_goods_util:get_null_cell_num(GoodsStatus, ?GOODS_LOC_BAG),
    if HasNullCell >= NeedNullCell ->
            true;
        true ->
            false
    end.

%% 计算拆分物品所需格子数
calc_need_null_cell_num(SpiltGoods) ->
    lists:foldl(fun({GoodsInfo, NeedSpilt}, Acc) ->
        case data_goods_type:get(GoodsInfo#goods.goods_id) of
            #ets_goods_type{max_overlap = MaxLap} ->
                util:ceil(NeedSpilt/MaxLap) + Acc;
            _ ->
                Acc
        end
    end, 0, SpiltGoods).

get_store_info(RoleId, UnlockIds, ReturnType) ->
    CanBuys = if UnlockIds == [] ->
            DefaultBuys = get_index_by_lock_type(?SUP_VIP_SOTRE_DEFAULT),
            UnlockId = lists:max(DefaultBuys),
            DefaultBuys;
        true ->
            DefaultBuys = get_index_by_lock_type(?SUP_VIP_SOTRE_DEFAULT),
            %% 有解锁要求的已解锁序列
            UnlockIds1 = UnlockIds -- DefaultBuys,
            MaxCanBuy = get_max_unlock_canbuy(UnlockIds),
            CanBuys0 = case lists:member(MaxCanBuy, UnlockIds1) of
                true -> UnlockIds1 ++ DefaultBuys;
                _    -> [MaxCanBuy|UnlockIds1] ++ DefaultBuys
            end,
            UnlockId = lists:max(CanBuys0),
            CanBuys0
    end,
    {UnLimitGoods, DailyGoods, WeekGoods, PerGoods} = get_goods_count_types(CanBuys),
    % ?ERR("~p ~p ~p ~p ~p", [CanBuys, UnLimitGoods, DailyGoods, WeekGoods, PerGoods]),
    MFA = {?MODULE, send_sup_vip_info, []},
    if DailyGoods =/= [] ->
            get_daily_data(RoleId, UnlockId, UnLimitGoods, DailyGoods, WeekGoods, PerGoods, ReturnType, MFA);
        true ->
            get_weekly_data(RoleId, UnlockId, UnLimitGoods, [], WeekGoods, PerGoods, ReturnType, MFA)
    end,
    ok.

get_goods_count_types(CanBuys) ->
    AllGoods = data_sup_vip:get_all_goods(),
     lists:foldl(fun(GoodsId, {UnLimitGoods, DailyGoods, WeekGoods, PerGoods}) ->
        case data_sup_vip:get_goods(GoodsId) of
            #base_sup_vip_store{index = Index, limit_buy = LimitBuys} ->
                case lists:member(Index, CanBuys) of
                    true ->
                        case LimitBuys of
                            [{?SUP_VIP_LIMIT_DAILY, _}|_] ->
                                {UnLimitGoods, [GoodsId|DailyGoods], WeekGoods, PerGoods};
                            [{?SUP_VIP_LIMIT_WEEK, _}|_] ->
                                {UnLimitGoods, DailyGoods, [GoodsId|WeekGoods], PerGoods};
                            [{?SUP_VIP_LIMIT_PERMANENT, _}|_] ->
                                {UnLimitGoods, DailyGoods, WeekGoods, [GoodsId|PerGoods]};
                            _ ->
                                {[GoodsId|UnLimitGoods], DailyGoods, WeekGoods, PerGoods}
                        end;
                    _ ->
                        {UnLimitGoods, DailyGoods, WeekGoods, PerGoods}
                end;
            _ ->
                {UnLimitGoods, DailyGoods, WeekGoods, PerGoods}
        end
     end, {[], [], [], []}, AllGoods).

get_daily_data(RoleId, UnlockId, UnLimitGoods, DailyGoods, WeekGoods, PerGoods, ReturnType, MFA) ->
    CountList = [{?MOD_SUP_VIP, ?SUP_VIP_DAILY_BUY_LIMIT, GoodsId1} || GoodsId1 <- DailyGoods],
    DailyCounts = lib_daily:get_count(RoleId, CountList),
    get_weekly_data(RoleId, UnlockId, UnLimitGoods, DailyCounts, WeekGoods, PerGoods, ReturnType, MFA).

get_weekly_data(RoleId, UnlockId, UnLimitGoods, DailyCounts, WeekGoods, PerGoods, ReturnType, MFA) ->
    if WeekGoods =/= [] ->
            CountList = [{?MOD_SUP_VIP, ?SUP_VIP_WEEK_BUY_LIMIT, GoodsId1} || GoodsId1 <- WeekGoods],
            WeekCounts = lib_week:get_count(RoleId, CountList);
        true ->
            WeekCounts = []
    end,
    get_permanent_data(RoleId, UnlockId, UnLimitGoods, DailyCounts, WeekCounts, PerGoods, ReturnType, MFA).


get_permanent_data(RoleId, UnlockId, UnLimitGoods, DailyCounts, WeekCounts, PerGoods, ReturnType, {Mod, Fun, Arg}) ->
    if PerGoods =/= [] ->
            CountList = [{?MOD_SUP_VIP, ?SUP_VIP_PER_BUY_LIMIT, GoodsId1} || GoodsId1 <- PerGoods],
            PerCounts = lib_counter:get_count(RoleId, CountList);
        true ->
            PerCounts = []
    end,
    Mod:Fun([RoleId, UnlockId, UnLimitGoods, DailyCounts, WeekCounts, PerCounts, ReturnType] ++ Arg).

get_lock_ids() ->
    AllGoods = data_sup_vip:get_all_goods(),
    lists:foldl(fun(GoodsId, Acc) ->
        case data_sup_vip:get_goods(GoodsId) of
            #base_sup_vip_store{type = UnlockType, index = Index} ->
                if UnlockType == ?SUP_VIP_SOTRE_DEFAULT ->
                        Acc;
                    true ->
                        [Index|Acc]
                end;
            _ ->
                Acc
        end
     end, [], AllGoods).

%% 当前所能购买的最大序列
get_max_unlock_canbuy(Unlocks) ->
    AllGoods = data_sup_vip:get_all_goods(),
    {DefaultBuys, NeedLocks} = lists:foldl(fun(GoodsId, {Default, NeedLock}) ->
        case data_sup_vip:get_goods(GoodsId) of
            #base_sup_vip_store{type = ?SUP_VIP_STORE_LOCK, index = Index} ->
                {Default, [Index|NeedLock]};
            #base_sup_vip_store{index = Index} ->
                {[Index|Default], NeedLock};
            _ ->
                {Default, NeedLock}
        end
    end, {[], []}, AllGoods),
    %% 已解锁的有解锁要求的序列
    Unlocks1 = Unlocks -- DefaultBuys,
    MaxUnlock = lists:max(Unlocks),
    case NeedLocks -- Unlocks1 of
        Result = [_|_] -> %% 未解锁的有解锁要求的序列
            MinNeedUnlock = lists:min(Result),
            case MaxUnlock+1 of
                MinNeedUnlock ->
                    MinNeedUnlock;
                _ ->
                    MaxUnlock
            end;
        _ ->
            lists:max(Unlocks1)
    end.

get_index_by_lock_type(Type) ->
    AllGoods = data_sup_vip:get_all_goods(),
    lists:foldl(fun(GoodsId, Acc) ->
        case data_sup_vip:get_goods(GoodsId) of
            #base_sup_vip_store{type = Type, index = Index} ->
                [Index|Acc];
            _ ->
                Acc
        end
     end, [], AllGoods).

send_sup_vip_info([RoleId, UnlockId, UnLimitGoods, DailyCounts, WeekCounts, PerCounts, ReturnType|_]) ->
    % ?ERR("~p ~p ~p", [UnLimitGoods, DailyCounts, WeekCounts]),
    AllGoodsCount = get_goods_limit_counts(UnLimitGoods, DailyCounts, WeekCounts, PerCounts),
    % ?ERR("~p", [AllGoodsCount]),
    lib_server_send:send_to_uid(RoleId, pt_451, 45104, [?SUCCESS, ReturnType, AllGoodsCount, UnlockId]),
    ok.

get_goods_limit_counts(UnLimitGoods, DailyCounts, WeekCounts, PerCounts) ->
    DailyCounts1 = [{?SUP_VIP_LIMIT_DAILY, GoodsId1, Count1} || {{_, _, GoodsId1}, Count1} <- DailyCounts],
    WeekCounts1  = [{?SUP_VIP_LIMIT_WEEK, GoodsId2, Count2} || {{_, _, GoodsId2}, Count2} <- WeekCounts],
    PerCounts1    = [{?SUP_VIP_LIMIT_PERMANENT, GoodsId3, Count3} || {{_, _, GoodsId3}, Count3} <- PerCounts],
    UnLimitCounts = [{0, GoodsId4, 0} || GoodsId4 <- UnLimitGoods],
    AllCounts = lists:append([DailyCounts1, WeekCounts1, PerCounts1, UnLimitCounts]),
    AllCounts.

%% 贵族限购商城购买
sup_vip_buy(GoodsId, GoodsNum, Player) ->
    #player_status{id = RoleId, sid = Sid, figure = #figure{lv = RoleLv}, vip_status = VipStatus} = Player,
    #vip_status{sup_vip = RoleSupVip} = VipStatus,
    #role_sup_vip{type = SupVipType, end_time = EndTime, unlock_ids = UnlockIds} = RoleSupVip,
    CheckL = [
        {is_sup_vip, SupVipType, EndTime},
        {unlock_goods_check, GoodsId, UnlockIds},
        {goods_limit_check, RoleId, RoleLv, GoodsId, GoodsNum, UnlockIds},
        {goods_price_check, GoodsId}
    ],
    case lib_vip_util:check(CheckL) of
        true ->
            #base_sup_vip_store{price = Price, index = Index, limit_buy = LimitBuys} = data_sup_vip:get_goods(GoodsId),
            case LimitBuys of
                 [{LimitType, _}|_] -> ok;
                 _ -> LimitType = 0
            end,
            Price1 = [{CurType, 0, round(Num*GoodsNum)} || {CurType, Num} <- Price],
            sup_vip_buy_do(Player, GoodsId, GoodsNum, LimitType, Price1, Index);
        {false, Errcode} ->
            lib_server_send:send_to_sid(Sid, pt_451, 45105, [Errcode]),
            ok
    end.

sup_vip_buy_do(Player, GoodsId, GoodsNum, LimitType, Cost, Index) ->
    case lib_goods_api:cost_object_list_with_check(Player, Cost, sup_vip_limit_buy_cost, "") of
        {true, NewPlayer, _} ->
            Rewards = [{?TYPE_GOODS, GoodsId, GoodsNum}],
            #player_status{id = RoleId, figure = #figure{name = RoleName, vip = VipLv}, vip_status = VipStatus} = NewPlayer1 = lib_goods_api:send_reward(NewPlayer, Rewards, sup_vip_limit_buy_rewrad),
            #vip_status{sup_vip = RoleSupVip} = VipStatus,
            #role_sup_vip{unlock_ids = UnlockIds} = RoleSupVip,
            {OldCount, Count} = increment_sup_vip_goods_limit_count(RoleId, LimitType, GoodsId, GoodsNum),
            NewUnlockIds = case lists:member(Index, UnlockIds) of
                true -> UnlockIds;
                _    -> [Index|UnlockIds]
            end,
            MaxCanBuy = get_max_unlock_canbuy(NewUnlockIds),
            MaxUnlockId  = max(lists:max(NewUnlockIds), MaxCanBuy),
            NewRoleSupVip = RoleSupVip#role_sup_vip{unlock_ids = NewUnlockIds},
            NewVipStatus = VipStatus#vip_status{sup_vip = NewRoleSupVip},
            db_update_role_sup_vip(RoleId, NewRoleSupVip),
            AllGoodsCount = [{LimitType, GoodsId, Count}],
            {ok, Bin} = pt_451:write(45104, [?SUCCESS, 1, AllGoodsCount, MaxUnlockId]),
            {ok, Bin1} = pt_451:write(45105, [?SUCCESS]),
            lib_server_send:send_to_uid(RoleId, <<Bin/binary, Bin1/binary>>),
            lib_log_api:log_sup_vip_exchange(RoleId, RoleName, VipLv, ?SUP_VIP_EXCHANGE_3, Cost, Rewards, OldCount, Count, Player#player_status.gold, NewPlayer1#player_status.gold),
            {ok, NewPlayer1#player_status{vip_status = NewVipStatus}};
        {false, Errcode, _} ->
            lib_server_send:send_to_sid(Player#player_status.sid, pt_451, 45105, [Errcode])
    end.

increment_sup_vip_goods_limit_count(RoleId, LimitType, GoodsId, Num) ->
    if LimitType == ?SUP_VIP_LIMIT_DAILY ->
            Count = lib_daily:get_count(RoleId, ?MOD_SUP_VIP, ?SUP_VIP_DAILY_BUY_LIMIT, GoodsId),
            lib_daily:plus_count(RoleId, ?MOD_SUP_VIP, ?SUP_VIP_DAILY_BUY_LIMIT, GoodsId, Num), %%increment(RoleId, ?MOD_SUP_VIP, ?SUP_VIP_DAILY_BUY_LIMIT, GoodsId),
            {Count, Count+Num};
        LimitType == ?SUP_VIP_LIMIT_WEEK ->
            Count = lib_week:get_count(RoleId, ?MOD_SUP_VIP, ?SUP_VIP_WEEK_BUY_LIMIT, GoodsId),
            lib_week:plus_count(RoleId, ?MOD_SUP_VIP, ?SUP_VIP_WEEK_BUY_LIMIT, GoodsId, Num),
            {Count, Count+Num};
        LimitType == ?SUP_VIP_LIMIT_PERMANENT ->
            Count = lib_counter:get_count(RoleId, ?MOD_SUP_VIP, ?SUP_VIP_PER_BUY_LIMIT, GoodsId),
            lib_counter:plus_count(RoleId,  ?MOD_SUP_VIP, ?SUP_VIP_PER_BUY_LIMIT, GoodsId, Num),
            {Count, Count+Num};
        true ->
            {0, 0}
    end.

calc_trial_sup_vip_end_time() ->
    MidNight = utime:unixdate(),
    SupVipLastDay = data_sup_vip:get_kv(trial_sup_vip),
    LastTime = round(SupVipLastDay*86400),
    EndTime  = MidNight+LastTime-1,
    {LastTime*1000, EndTime}.

test() ->
    Now = utime:unixtime(),
    SupVipLastDay = data_sup_vip:get_kv(trial_sup_vip),
    LastTime = calc_last_time(SupVipLastDay, Now, 0),
    EndTime = Now + LastTime,
    {LastTime, EndTime}.

calc_last_time(0, _Time, Acc) -> Acc;
calc_last_time(LastDay, Time, Acc) ->
    NextTime = utime:unixtime({tomorrow, Time}),
    NewAcc = if LastDay == 1 ->
            NextTime - Time - 1 + Acc;
        true ->
            NextTime - Time + Acc
    end,
    calc_last_time(LastDay-1, NextTime, NewAcc).

%% 星钻增加
-spec add_star(Player, Money) -> NewPlayer when
    Player :: #player_status{},
    Money  :: integer() | float(),
    NewPlayer :: #player_status{}.
add_star(Player, Money) ->
    #player_status{id = RoleId, sid = Sid, vip_status = RoleVip, figure = #figure{lv = Lv, vip = Vip}} = Player,
    #vip_status{sup_vip = RoleSupVip} = RoleVip,
    #role_sup_vip{today_star = Star, update_time = Time} = RoleSupVip,
    Now = utime:unixtime(),
    ProduceType = data_goods:get_produce_type(recharge),
    CurrencyId = ?TYPE_STAR,
    case utime:is_same_day(Time, Now) of
        true ->
            mod_log:add_log(log_produce_currency, [Now, ProduceType, RoleId, Lv, Vip, CurrencyId, round(Money), round(Star+Money), ""]),
            NewRoleSupVip = RoleSupVip#role_sup_vip{today_star = round(Star+Money), update_time = Now};
        _ ->
            mod_log:add_log(log_produce_currency, [Now, ProduceType, RoleId, Lv, Vip, CurrencyId, round(Money), round(Money), ""]),
            NewRoleSupVip = RoleSupVip#role_sup_vip{today_star = round(Money), update_time = Now}
    end,
    lib_server_send:send_to_sid(Sid, pt_451, 45106, [?SUCCESS, NewRoleSupVip#role_sup_vip.today_star]),
    db_update_role_sup_vip(RoleId, NewRoleSupVip),
    NewRoleVip = RoleVip#vip_status{sup_vip = NewRoleSupVip},
    NewPlayer = Player#player_status{vip_status = NewRoleVip},
    RemindNum = data_sup_vip:get_kv(remind_num),
    if NewRoleSupVip#role_sup_vip.today_star >= RemindNum ->
            lib_server_send:send_to_sid(Sid, pt_451, 45108, []);
        true -> skip
    end,
    NewPlayer.

-spec cost_star(Player, GoodsNum, Type, _About) -> ReturnType when
    Player :: #player_status{},
    GoodsNum :: integer(),
    Type :: integer() | term(),
    _About :: term(),
    ReturnType :: #player_status{}.
cost_star(Player, GoodsNum, Type, _About) ->
    #player_status{id = RoleId, sid = Sid, vip_status = VipStatus, figure = #figure{lv = RoleLv, vip = VipLv}} = Player,
    #vip_status{sup_vip = RoleSupVip} = VipStatus,
    #role_sup_vip{today_star = Star} = RoleSupVip,
    NewStar = max(0, round(Star-GoodsNum)),
    NewRoleSupVip = RoleSupVip#role_sup_vip{today_star = NewStar},
    db_update_role_sup_vip(RoleId, NewRoleSupVip),
    NewRoleVip = VipStatus#vip_status{sup_vip = NewRoleSupVip},
    NewPlayer = Player#player_status{vip_status = NewRoleVip},
    lib_log_api:log_consume_currency(RoleId, RoleLv, VipLv, Type, ?TYPE_STAR, GoodsNum, NewStar, _About),
    lib_server_send:send_to_sid(Sid, pt_451, 45106, [?SUCCESS, NewStar]),
    NewPlayer.

%% 星钻是否足够
-spec is_enough_star(Player, GoodsNum) -> ReturnType when
    Player :: #player_status{},
    GoodsNum :: integer(),
    ReturnType :: boolean().
is_enough_star(Player, GoodsNum) ->
    #player_status{vip_status = VipStatus} = Player,
    #vip_status{sup_vip = RoleSupVip} = VipStatus,
    #role_sup_vip{today_star = Star, update_time = Time} = RoleSupVip,
    Now = utime:unixtime(),
    case utime:is_same_day(Time, Now) of
        true ->
            Star >= GoodsNum;
        _ ->
            false
    end.

%% 是否是贵族身份(含体验)
-spec is_sup_vip(Parameters) -> ReturnType when
    Parameters :: #player_status{} | #vip_status{} | #role_sup_vip{},
    ReturnType :: boolean().
is_sup_vip(Player) when is_record(Player, player_status) ->
    #player_status{vip_status = VipStatus} = Player,
    #vip_status{sup_vip = RoleSupVip} = VipStatus,
    is_sup_vip(RoleSupVip);
is_sup_vip(VipStatus) when is_record(VipStatus, vip_status) ->
    #vip_status{sup_vip = RoleSupVip} = VipStatus,
    is_sup_vip(RoleSupVip);
is_sup_vip(RoleSupVip) when is_record(RoleSupVip, role_sup_vip) ->
    #role_sup_vip{type = SupVipType} = RoleSupVip,
    if SupVipType == ?PER_SUP_VIP orelse SupVipType == ?TRIAL_SUP_VIP ->
            true;
        true -> false
    end;
is_sup_vip(_) -> false.

%% 是否是永久贵族
-spec is_per_sup_sip(Parameters) -> ReturnType when
    Parameters :: #player_status{} | #vip_status{} | #role_sup_vip{},
    ReturnType :: boolean().
is_per_sup_sip(Player) when is_record(Player, player_status) ->
    #player_status{vip_status = VipStatus} = Player,
    #vip_status{sup_vip = RoleSupVip} = VipStatus,
    is_per_sup_sip(RoleSupVip);
is_per_sup_sip(VipStatus) when is_record(VipStatus, vip_status) ->
    #vip_status{sup_vip = RoleSupVip} = VipStatus,
    is_per_sup_sip(RoleSupVip);
is_per_sup_sip(RoleSupVip) when is_record(RoleSupVip, role_sup_vip) ->
    #role_sup_vip{type = SupVipType} = RoleSupVip,
    if SupVipType == ?PER_SUP_VIP ->
            true;
        true ->
            false
    end.

%% 获取贵族类型
-spec sup_vip_type(Parameters) -> ReturnType when
    Parameters :: #player_status{} | #vip_status{} | #role_sup_vip{} | undefined,
    ReturnType :: ?NO_SUP_VIP | ?TRIAL_SUP_VIP | ?PER_SUP_VIP.
sup_vip_type(Player) when is_record(Player, player_status) ->
    sup_vip_type(Player#player_status.vip_status);
sup_vip_type(RoleVip) when is_record(RoleVip, vip_status) ->
    sup_vip_type(RoleVip#vip_status.sup_vip);
sup_vip_type(RoleSupVip) when is_record(RoleSupVip, role_sup_vip) ->
    RoleSupVip#role_sup_vip.type;
sup_vip_type(undefined) ->
    ?NO_SUP_VIP.

%% 是否有特殊被动技能
get_sup_vip_skill(Player) ->
    case is_sup_vip(Player) of
        true ->
            [{?SUPVIP_FORBID_JUMP_SKILL, 1}];
        _ ->
            []
    end.

%% 获取贵族的特殊被动技能
get_sup_vip_skill() ->
    [{?SUPVIP_FORBID_JUMP_SKILL, 1}].

calc_gold_exchange(_, []) ->
    0;
calc_gold_exchange(VipLv, [{[MinVip, MaxVip|_], ExchangeCount}|Rest]) ->
    if VipLv >= MinVip andalso VipLv =< MaxVip ->
            ExchangeCount;
        true ->
            calc_gold_exchange(VipLv, Rest)
    end.

calc_goods_exchange(_VipLv, [{_MaxVip, ConfigCount}]) ->
    ConfigCount;
calc_goods_exchange(VipLv, [{MaxVip, ConfigCount}|Rest]) ->
    if VipLv =< MaxVip ->
            ConfigCount;
        true ->
            calc_goods_exchange(VipLv, Rest)
    end.

%% 激活体验贵族第几天
get_day(_EndTime) -> 0.

get_sup_vip_star(Player) ->
    #player_status{sid = Sid, vip_status = VipStatus} = Player,
    #vip_status{sup_vip = RoleSupVip} = VipStatus,
    case RoleSupVip of
        #role_sup_vip{update_time = UpdateTime, today_star = TodayStar} ->
            case utime:is_today(UpdateTime) of
                true ->
                    lib_server_send:send_to_sid(Sid, pt_451, 45106, [?SUCCESS, TodayStar]);
                _ ->
                    lib_server_send:send_to_sid(Sid, pt_451, 45106, [?SUCCESS, 0])
            end;
        _ ->
            lib_server_send:send_to_sid(Sid, pt_451, 45106, [?SUCCESS, 0])
    end.

gm_reset_supvip(Player) ->
    #player_status{id = RoleId, vip_status = VipStatus, figure = Figure} = Player,
    #vip_status{sup_vip = RoleSupVip} = VipStatus,
    case RoleSupVip of
        #role_sup_vip{} ->
            NewRoleSupVip = #role_sup_vip{},
            db_update_role_sup_vip(RoleId, NewRoleSupVip),
            % lib_player_record:role_func_check_delete_sub_id(RoleId, ?FUNC_TYPE_SUP_VIP, ?FUNC_TYPE_SUP_VIP_1),
            lib_role:update_role_show(RoleId, [{sup_vip, ?NO_SUP_VIP}]),
            NewPlayer = Player#player_status{figure = Figure#figure{sup_vip = ?NO_SUP_VIP}, vip_status = VipStatus#vip_status{sup_vip = NewRoleSupVip}},
            reset_sup_vip_count(RoleId),
            pp_sup_vip:handle(45101, NewPlayer, []),
            mod_scene_agent:update(NewPlayer, [{delete_passive_skill, get_sup_vip_skill()}]),
            NewPlayer1 = lib_player:count_player_attribute(NewPlayer, ?MOD_SUP_VIP),
            lib_player:send_attribute_change_notify(NewPlayer1, ?NOTIFY_ATTR),
            lib_skill:send_my_skill_list(NewPlayer),
            NewPlayer1;
        _ ->
            Player
    end.

reset_sup_vip_count(RoleId) ->
    %% 日常兑换次数
    DailyList = [{{?MOD_SUP_VIP, ?SUP_VIP_DAILY_EXCHANGE, ?SUP_VIP_GIFT_EXCHANGE}, 0}],
    lib_daily:set_count(RoleId, DailyList),
    %% 道具限购清理
    case data_sup_vip:get_all_goods() of
        Goods = [_|_] ->
            {DailyList1, WeekList1, PerList1} = lists:foldl(fun(GoodsId, {Acc1, Acc2, Acc3}) ->
                case data_sup_vip:get_goods(GoodsId) of
                    #base_sup_vip_store{limit_buy = [{LimitType, _}|_]} ->
                        if LimitType == ?SUP_VIP_LIMIT_DAILY ->
                                {[{{?MOD_SUP_VIP, ?SUP_VIP_DAILY_BUY_LIMIT, GoodsId}, 0}|Acc1], Acc2, Acc3};
                            LimitType == ?SUP_VIP_LIMIT_WEEK ->
                                {Acc1, [{{?MOD_SUP_VIP, ?SUP_VIP_WEEK_BUY_LIMIT, GoodsId}, 0}|Acc2], Acc3};
                            LimitType == ?SUP_VIP_LIMIT_PERMANENT ->
                                {Acc1, Acc2, [{{?MOD_SUP_VIP, ?SUP_VIP_PER_BUY_LIMIT, GoodsId}, 0}|Acc3]};
                            true ->
                                {Acc1, Acc2, Acc3}
                        end;
                    _ ->
                        {Acc1, Acc2, Acc3}
                end
             end, {[], [], []}, Goods),
            % ?ERR("~p ~p", [DailyList1, WeekList1]),
            DailyList1 =/= [] andalso lib_daily:set_count(RoleId, DailyList1),
            WeekList1 =/= [] andalso lib_week:set_count(RoleId, WeekList1),
            PerList1 =/= [] andalso lib_counter:set_count(RoleId, PerList1);
        _ ->
            skip
    end.

%% 七天礼包状态
login_rewards_status(Player) ->
    #player_status{sid = Sid, vip_status = VipStatus} = Player,
    #vip_status{sup_vip = RoleSupVip} = VipStatus,
    #role_sup_vip{login_rewards = LoginRewards} = RoleSupVip,
    RewardsList = lists:foldl(fun({Day, RewardTime, RewardState}, Acc) -> 
        if RewardTime == 0 -> 
                [{Day, 0}|Acc];
            RewardTime =/= 0 andalso RewardState == 0 ->
                [{Day, 1}|Acc];
            RewardState =/= 0 ->
                [{Day, 2}|Acc];
            true -> Acc
        end
    end, [], LoginRewards),
    LoginDays = calc_login_day(LoginRewards),
    % ?ERR("~p ~p", [RewardsList, LoginDays]),
    {ok, BinData} = pt_451:write(45109, [RewardsList, LoginDays]),
    lib_server_send:send_to_sid(Sid, BinData),
    ok.

%% 获取七天礼包
get_login_rewards(Player, Day, Type) ->
    #player_status{id = RoleId, sid = Sid, vip_status = VipStatus} = Player,
    #vip_status{sup_vip = RoleSupVip} = VipStatus,
    #role_sup_vip{login_rewards = LoginRewards, last_reward_rec = LastRewardRec} = RoleSupVip,
    SupVipType = sup_vip_type(RoleSupVip),
    case lists:keyfind(Day, 1, LoginRewards) of
        {_, RewardTime, RewardState} ->
            if 
                Type == 1 andalso RewardTime =/= 0 ->
                    lib_server_send:send_to_sid(Sid, pt_451, 45110, [?ERRCODE(reward_is_got)]);
                Type == 2 andalso RewardState =/= 0 ->
                    lib_server_send:send_to_sid(Sid, pt_451, 45110, [?ERRCODE(reward_is_got)]);
                Type == 2 andalso RewardTime == 0 ->
                    lib_server_send:send_to_sid(Sid, pt_451, 45110, [?ERRCODE(err451_need_first_reward)]);
                Type =/= 1 andalso Type =/= 2 ->
                    lib_server_send:send_to_sid(Sid, pt_451, 45110, [?FAIL]);
                SupVipType =/= ?PER_SUP_VIP andalso Type == 2 ->
                    lib_server_send:send_to_sid(Sid, pt_451, 45110, [?ERRCODE(err451_permanent_sup_vip)]);
                SupVipType == ?NO_SUP_VIP andalso Type == 1 ->
                    lib_server_send:send_to_sid(Sid, pt_451, 45110, [?FAIL]);
                LastRewardRec =/= 0 ->
                    lib_server_send:send_to_sid(Sid, pt_451, 45110, [?FAIL]);
                true -> %% 
                    % ?ERR("get_login_rewards ~p ~p ~p", [Type, RewardTime, RewardState]),
                    Now = utime:unixtime(),
                    if Type == 1 -> RewardTime1 = Now, RewardState1 = RewardState;
                        true -> RewardTime1 = RewardTime, RewardState1 = 1
                    end,
                    Rewards = get_day_rewards(Day),
                    Player1 = lib_goods_api:send_reward(Player, Rewards, sup_vip_login_rewards),
                    LoginRewards1 = lists:keystore(Day, 1, LoginRewards, {Day, RewardTime1, RewardState1}),
                    LastTime1 = calc_last_reward_rec(LoginRewards1),
                    RoleSupVip1 = RoleSupVip#role_sup_vip{login_rewards = LoginRewards1, last_reward_rec = LastTime1},
                    db_update_role_sup_vip(RoleId, RoleSupVip1),
                    VipStatus1 = VipStatus#vip_status{sup_vip = RoleSupVip1},
                    Player2 = Player1#player_status{vip_status = VipStatus1},
                    lib_server_send:send_to_sid(Sid, pt_451, 45110, [?SUCCESS]),
                    {ok, Player2}
            end;
        _ ->
            lib_server_send:send_to_sid(Sid, pt_451, 45110, [?FAIL]),
            ok
    end.

%% 查看所有奖励是否已领
calc_last_reward_rec(LoginRewards) ->
    RewardLen = length(LoginRewards),
    IsAllRewarded = lists:all(fun({_, _, RewardState}) -> 
        RewardState =/= 0 end, LoginRewards),
    if
        RewardLen >= ?BASE_SVIP_LOGIN_REWARD_DAY andalso IsAllRewarded ->
            1;
        true ->
            0
    end.

calc_login_day(LoginRewards) ->
    case lists:keyfind(0, 2, LoginRewards) of
        {_, _, _} ->
            length(LoginRewards);
        _ ->
            case lists:reverse(lists:keysort(1, LoginRewards)) of
                [{_MaxDay, RewardTime, _}|_] ->
                    case utime:is_today(RewardTime) of
                        true -> length(LoginRewards);
                        _ -> length(LoginRewards)+1
                    end;
                _ ->
                    0
            end
    end.

update_sup_vip_login_data(RoleId, RoleSupVip, Now) ->
    #role_sup_vip{
        type = SupVipType,
        login_rewards = LoginRewards,
        last_reward_rec = LastTime
    } = RoleSupVip,
    if
        SupVipType == ?NO_SUP_VIP ->
            RoleSupVip;
        true -> %% 至少一阶贵族以上
            {Update, LoginRewards2, LastTime1} =
            case lists:reverse(lists:keysort(1, LoginRewards)) of
                [{_MaxDay, 0, _RewardState}|_] ->
                    {false, LoginRewards, 0};
                [{_MaxDay, RewardTime, _RewardState}|_] ->
                    case utime:is_same_day(RewardTime, Now) of
                        true ->
                            {false, LoginRewards, 0};
                        _A ->
                            LoginLen = length(LoginRewards),
                            if 
                                LoginLen >= ?BASE_SVIP_LOGIN_REWARD_DAY andalso LastTime == 0 -> %% 已经过了7天了还未检测
                                    {LoginRewards1, Rewards} = calc_login_reward(LoginRewards, SupVipType),
                                    if Rewards == [] -> %% 没有奖励了
                                            {false, LoginRewards, 1};
                                        true ->
                                            Title = Content = <<"贵族七天登录礼包补发"/utf8>>,
                                            lib_mail_api:send_sys_mail([RoleId], Title, Content, Rewards),
                                            {true, LoginRewards1, 1}
                                    end;
                                LoginLen >= ?BASE_SVIP_LOGIN_REWARD_DAY -> %% 过了7天且已经检测过了
                                    {false, LoginRewards, 0};
                                true -> %% 还未领够7天不考虑补发情况
                                    LoginRewards1 = [{LoginLen+1, 0, 0}|LoginRewards],
                                    {true, LoginRewards1, 0}
                            end
                    end;
                [] ->
                    {true, [{1, 0, 0}], 0}
            end,
            if
                Update ->
                    RoleSupVip1 = RoleSupVip#role_sup_vip{login_rewards = LoginRewards2},
                    RoleSupVip1;
                true ->
                    RoleSupVip1 = RoleSupVip
            end,
            if
                LastTime1 =/= 0 ->
                    RoleSupVip2 = RoleSupVip1#role_sup_vip{last_reward_rec = LastTime1};
                true ->
                    RoleSupVip2 = RoleSupVip1
            end,
            if Update == true orelse LastTime1 =/= 0 -> 
                    db_update_role_sup_vip(RoleId, RoleSupVip2);
                true ->
                    skip
            end,
            RoleSupVip2
    end.

calc_login_reward(LoginRewards, ?TRIAL_SUP_VIP) ->
    {LoginRewards, []};
calc_login_reward(LoginRewards, ?PER_SUP_VIP) ->
    {LoginRewards1, Rewards1} =
    lists:foldl(fun({DayId, RewardTime, RewardState}, {AccLoginRewards, AccRewards}) -> 
        if 
            RewardState == 0 ->
                Rewards = get_day_rewards(DayId),
                {[{DayId, RewardTime, 1}|AccLoginRewards], lists:append(Rewards, AccRewards)};
            true ->
                {[{DayId, RewardTime, RewardState}|AccLoginRewards], AccRewards}
        end
    end, {[], []}, LoginRewards),
    {LoginRewards1, Rewards1}.

get_day_rewards(1) ->
    data_sup_vip:get_kv(sup_vip_gift_1);
get_day_rewards(2) ->
    data_sup_vip:get_kv(sup_vip_gift_2);
get_day_rewards(3) ->
    data_sup_vip:get_kv(sup_vip_gift_3);
get_day_rewards(4) ->
    data_sup_vip:get_kv(sup_vip_gift_4);
get_day_rewards(5) ->
    data_sup_vip:get_kv(sup_vip_gift_5);
get_day_rewards(6) ->
    data_sup_vip:get_kv(sup_vip_gift_6);
get_day_rewards(7) ->
    data_sup_vip:get_kv(sup_vip_gift_7);
get_day_rewards(_) ->
    [].
