%%%--------------------------------------
%%% @Module  : lib_vip
%%% @Author  : ywf
%%% @Created : 2019-4-9
%%% @Description:  vip
%%%--------------------------------------
-module(lib_vip).
-include("server.hrl").
-include("figure.hrl").
-include("errcode.hrl").
-include("vip.hrl").
-include("predefine.hrl").
-include("common.hrl").
-include("def_goods.hrl").
-include("def_module.hrl").
-include("def_event.hrl").
-include("goods.hrl").
-include("def_fun.hrl").
-include("def_vip.hrl").
-include("def_daily.hrl").
-include("customer_service.hrl").

-export([
    login/1,
    set_time_out_caller/1,
    set_time_out_caller_do/2,
    get_service_cfg/1,
    get_key_service_cfg/1,
    get_vip_privilege/5,
    get_vip_privilege/6,

    calc_vip_status/2,
    calc_vip_status/3,
    set_new_vip_figure/1,

    trial_vip_timeout/1
    ]).

-export([
    send_vip_info/1
    ,get_total_vip_exp/1
    ]).

-export([
    calc_up_next_vip_exp/2,
    vip_progress/3
    ]).

login(RoleId) ->
    VipStatus0 = lib_vip_util:db_select_vip(RoleId),
    RoleSupVip = lib_sup_vip:login(RoleId),
    VipStatus  = VipStatus0#vip_status{sup_vip = RoleSupVip},
    NewVipStatus = set_time_out_caller_do(RoleId, VipStatus),
    NewVipStatus.

%% 体验卡超时刷新vip_status
refresh_vip(PS, VipStatus) ->
    %% 更新vip到期计时器
    NewVipStatus = set_time_out_caller_do(PS#player_status.id, VipStatus),
    %% 更新数据库
    if NewVipStatus =/= VipStatus ->
            lib_vip_util:db_update_vip(PS#player_status.id, NewVipStatus);
        true ->
            skip
    end,
    %% 修改figure中的vip类型和等级
    NewPS = if NewVipStatus#vip_status.lv =/= VipStatus#vip_status.lv ->
            set_new_vip_figure(PS#player_status{vip_status = NewVipStatus});
        true ->
            PS#player_status{vip_status = NewVipStatus}
    end,
    {NewPS, NewVipStatus}.

%% 过期提醒定时器更新
set_time_out_caller(PS) when is_record(PS, player_status) ->
    #player_status{id = RoleId, vip_status = VipStatus} = PS,
    #vip_status{endtime = EndTime} = VipStatus,
    NowTime = utime:unixtime(),
    SetTimerVipStatus = ?IF(EndTime > NowTime, set_time_out_caller_do(RoleId, VipStatus), VipStatus),
    PS#player_status{vip_status = SetTimerVipStatus}.

set_time_out_caller_do(RoleId, VipStatus) ->
    #vip_status{endtime = EndTime} = VipStatus,
    NowTime = utime:unixtime(),
    case EndTime > NowTime of
        true  ->
            lib_player_record:role_func_check_update(RoleId, ?FUNC_TYPE_VIP, {?FUNC_TYPE_VIP_1, EndTime}),
            VipStatus#vip_status{type = ?VIP_TRIAL};
        false ->
            lib_player_record:role_func_check_delete(RoleId, ?FUNC_TYPE_VIP),
            VipStatus#vip_status{type = ?VIP_NORMAL, trial_lv = 0, endtime = 0}
    end.

%% 检测突破&升级
%% 判断是否处于体验卡阶段,若真实等级大于等于体验等级则转为正式真实等级
calc_vip_status(Player, GoldAdd) ->
    calc_vip_status(Player, GoldAdd, false).

calc_vip_status(Player, GoldAdd, IsChargeCard) ->
    #player_status{id = RoleId, vip_status = VipStatus} = Player,
    #vip_status{trial_lv = VipLv, lv = RealLv, exp = VipExp, type = VipType, endtime = EndTime} = VipStatus,
    {NewRealLv, NewVipExp, NewVipLv, NewVipType, NewEndTime} = calc_new_lv(VipType, VipLv, RealLv, VipExp, EndTime, GoldAdd),
    update_timeout_ref(VipType, NewVipType, RoleId),
    NowTime = utime:unixtime(),
    NewVipStatus = VipStatus#vip_status{trial_lv = NewVipLv, lv = NewRealLv, exp = NewVipExp, type = NewVipType, endtime = NewEndTime},
    lib_vip_util:db_update_vip(RoleId, NewVipStatus),
    NewPlayer = Player#player_status{vip_status = NewVipStatus},
    %% 升级奖励
    % send_vip_up_reward(RoleId, RealLv, NewRealLv),
    %% 升级触发检查
    NewPlayer3 = check_real_lv_up_trigger({VipType, RealLv, VipLv}, IsChargeCard, NewPlayer),
    %% 日志
    if VipType =/= NewVipType -> 
            lib_log_api:log_vip_status(RoleId, NewVipType, NewVipLv, NewRealLv, 0, ?VIP_LOG_1, NewEndTime, NowTime);
        true ->
            if NewRealLv =/= RealLv ->
                    lib_log_api:log_vip_status(RoleId, NewVipType, NewVipLv, NewRealLv, 0, ?VIP_LOG_3, NewEndTime, NowTime);
                true ->
                    skip
            end
    end,
    lib_log_api:log_vip_upgrade(RoleId, NewVipType, NewRealLv, NewVipExp, GoldAdd, NowTime),
    %% 推送更新
    send_vip_info(NewPlayer3),
    NewPlayer3.

%% 真实等级变动
check_real_lv_up_trigger({OldVipType, OldLv, OldTrialLv}, IsChargeCard, Player) ->
    #player_status{id = RoleId, figure = #figure{name = RoleName}, vip_status = VipStatus} = Player,
    #vip_status{lv = Lv} = VipStatus,
    if OldLv =/= Lv ->
            NewPlayer0 = set_new_vip_figure(Player),
            mod_scene_agent:update(NewPlayer0, [{vip, Lv}]),
            {ok, NewPlayer1} = lib_player_event:dispatch(NewPlayer0, ?EVENT_VIP, {OldLv, OldVipType, OldTrialLv}),
            #base_vip_cfg{name = Name} = data_vip:get_vip(Lv),
            not IsChargeCard andalso lib_chat:send_TV({all}, ?MOD_VIP, 1, [RoleName, RoleId, Name]),
            NewPlayer1;
        true ->
            Player
    end.

%% 体验vip过期
trial_vip_timeout(Player) ->
    #player_status{id = RoleId, sid = Sid, vip_status = VipStatus} = Player,
    #vip_status{endtime = EndTime} = VipStatus,
    NowTime = utime:unixtime(),
    case EndTime > NowTime of
        true  -> Player;
        false ->
            {SetFigurePlayer, LastVipStatus} = refresh_vip(Player, VipStatus),
            % ExpDropPlayer = lib_player:update_exp_dun_drop_ratio(SetFigurePlayer),
            % NewPlayer     = lib_player:update_exp_add_ratio(ExpDropPlayer),
            % TotalExp = lib_vip:get_total_vip_exp(LastVipStatus),
            %% 日志
            #vip_status{type = VipType, trial_lv = TrialLv, lv = Lv, endtime = EndTime1} = LastVipStatus,
            {ok, NewPlayer} = lib_player_event:dispatch(SetFigurePlayer, ?EVENT_VIP_TIME_OUT, []),
            lib_log_api:log_vip_status(RoleId, VipType, TrialLv, Lv, 0, ?VIP_LOG_2, EndTime1, NowTime),
            % {ok, BinData} = pt_450:write(45001, [LastVipStatus#vip_status.lv, TotalExp, LastVipStatus#vip_status.endtime]),
            {ok, BinData1} = pt_450:write(45003, [1]),
            lib_server_send:send_to_sid(Sid, BinData1),
            NewPlayer
    end.

% send_vip_up_reward(RoleId, VipLv, NewVipLv) ->
%     if NewVipLv =/= VipLv andalso NewVipLv =/= 0 ->
%             case data_vip:get_vip(NewVipLv) of
%                 #base_vip_cfg{reward = Rewards} ->
%                     Title   = utext:get(?VIP_TITLE),
%                     #base_vip_cfg{name = Name} = data_vip:get_vip(NewVipLv),
%                     Content = uio:format(data_language:get(?VIP_CONTENT), [Name]),
%                     lib_mail_api:send_sys_mail([RoleId], Title, Content, Rewards);
%                 _ ->
%                     ?ERR("vip lv error ~p ~p", [VipLv, NewVipLv])
%             end;
%         true ->
%             skip
%     end.

calc_new_lv(VipType, VipLv, RealLv, VipExp, EndTime, GoldAdd) ->
    MaxVip = data_vip:get_max_vip(),
    if RealLv >= MaxVip ->
            {RealLv, round(VipExp+GoldAdd), VipLv, VipType, EndTime};
        true ->
            NeedExp = calc_up_next_vip_exp(RealLv, VipExp),
            % ?ERR("init vip type ~p need ~p init vip exp ~p init vip lv ~p", [VipType, NeedExp,VipExp, RealVipLv]),
            if GoldAdd < NeedExp -> %% 未达到升级条件
                    {RealLv, round(VipExp+GoldAdd), VipLv, VipType, EndTime};
                true ->
                    {NewRealVipLv, NewVipExp} = vip_progress(RealLv, GoldAdd, NeedExp),
                    if VipType == ?VIP_NORMAL ->
                            NewVipType = VipType,
                            NewEndTime = EndTime,
                            NewVipLv = 0;
                        true ->
                            if NewRealVipLv >= VipLv -> %% 充值的真实等级已达到体验VIP等级,转为正式
                                    NewVipType = ?VIP_NORMAL,
                                    NewEndTime = 0,
                                    NewVipLv = 0;
                                true ->
                                    NewVipType = VipType,
                                    NewEndTime = EndTime,
                                    NewVipLv = VipLv
                            end
                    end,
                    {NewRealVipLv, NewVipExp, NewVipLv, NewVipType, NewEndTime}
            end
    end.

vip_progress(VipLv, GoldAdd, NeedExp) ->
    RestGoldAdd = max(0, GoldAdd - NeedExp),
    NewVipLv = VipLv + 1,
    NewVipExp = 0,
    NewNeedExp = calc_up_next_vip_exp(NewVipLv, NewVipExp),
    % ?ERR("new rest ~p new lv ~p new exp ~p new need exp ~p", [RestGoldAdd, NewVipLv, NewVipExp, NewNeedExp]),
    if RestGoldAdd >= NewNeedExp ->
            MaxVip = data_vip:get_max_vip(),
            if NewVipLv >= MaxVip ->
                    % ?ERR("~p ~p ~p ~p", [NewVipLv, NeedExp, NewNeedExp, RestGoldAdd]),
                    {NewVipLv, max(NewNeedExp, RestGoldAdd)};
                true ->
                    vip_progress(NewVipLv, RestGoldAdd, NewNeedExp)
            end;
        true ->
            {NewVipLv, RestGoldAdd}
    end.


%% 检测取消体验式VIP超时定时器
%% 是否因充值而成为正式VIP,是的话要将体验VIP定时器去除
update_timeout_ref(VipType, NewVipType, RoleId) ->
    if VipType == ?VIP_TRIAL andalso
     NewVipType == ?VIP_NORMAL ->
            lib_player_record:role_func_check_delete(RoleId, ?FUNC_TYPE_VIP);
        true ->
            skip
    end.

get_vip_exp(VipLv) ->
    VipExp = case data_vip:get_vip(VipLv) of
        #base_vip_cfg{gold = Gold} ->
            Gold;
        _ ->
            0
    end,
    VipExp.

get_total_vip_exp(VipStatus) ->
    #vip_status{lv = Lv, exp = VipExp} = VipStatus,
    case data_vip:get_vip(Lv) of
        #base_vip_cfg{gold = Gold} ->
            round(Gold+VipExp);
        _ ->
            VipExp
    end.

%% 计算升级到下一vip等级所需经验
calc_up_next_vip_exp(VipLv, VipExp) ->
    VipExp1 = get_vip_exp(VipLv),
    NextVipLv = VipLv+1,
    NextVipExp = get_vip_exp(NextVipLv),
    max(0, NextVipExp - VipExp1 - VipExp).

%% 更新用户外形
set_new_vip_figure(PS) ->
    #player_status{figure = Figure} = PS,
    #vip_status{lv = Lv} = PS#player_status.vip_status,
    NewFigure = Figure#figure{vip = Lv},
    SetFigurePS = PS#player_status{figure = NewFigure},
    lib_role:update_role_show(SetFigurePS#player_status.id, [{vip, Lv}]),
    SetFigurePS.

%% 发送vip信息
send_vip_info(PS) ->
    #player_status{id = RoleId, vip_status = #vip_status{lv = RealLv, trial_lv = VipLv, endtime = VipEndTime} = VipStatus} = PS,
    TotalVipExp = get_total_vip_exp(VipStatus),
    LvRewards = get_access_vip_lv_reward(RoleId, RealLv),
    % ?ERR("~p ~p", [RealLv, TotalVipExp]),
    lib_server_send:send_to_sid(PS#player_status.sid, pt_450, 45001, [RealLv, VipLv, TotalVipExp, VipEndTime, LvRewards]).

%% 获取vip特权
get_vip_privilege(RealLv, IsTrial, VipLv, ClassId, SubclassId) ->
    get_vip_privilege(RealLv, IsTrial, VipLv, ClassId, SubclassId, 1).

get_vip_privilege(RealLv, IsTrial, VipLv, ClassId, SubclassId, PrivilegeId) ->
    do_get_vip_privilege(RealLv, IsTrial, VipLv, ClassId, SubclassId, PrivilegeId).

do_get_vip_privilege(RealLv, IsTrial, VipLv, ClassId, SubclassId, PrivilegeId) ->
    % ?ERR("~p ~p ~p ~p", [RealLv, IsTrial, VipLv, ClassId]),
    if IsTrial == ?VIP_TRIAL ->
            RealVal  = get_privilege_vip_class(RealLv, ?VIP_NORMAL, ClassId, SubclassId, PrivilegeId),
            TrialVal = get_privilege_vip_class(VipLv, IsTrial, ClassId, SubclassId, PrivilegeId),
            max(RealVal, TrialVal);
        true ->
            get_privilege_vip_class(RealLv, IsTrial, ClassId, SubclassId, PrivilegeId)
    end.

get_privilege_vip_class(VipLv, IsTrial, ClassId, SubclassId, PrivilegeId) ->
    %% 在当前等级下及指定功能id下的所有特权
    case data_vip:get_access_vip(ClassId, SubclassId, PrivilegeId) of
        VipPrivileges = [_|_] ->
            case lists:filter(fun({VipLvX, _ValX, _CanTry}) -> 
                VipLv >= VipLvX
            end, VipPrivileges) of
                FilterPrivileges = [_|_] ->
                    SortPrivileges = lists:keysort(1, FilterPrivileges),
                    calc_privilege_val(lists:reverse(SortPrivileges), IsTrial);
                _ ->
                    0
            end;
        _ ->
            0
    end.

calc_privilege_val([], _) -> 0;
calc_privilege_val([{_Vip, PriVal, CanTry}|L], IsTrial) ->
    if IsTrial == ?VIP_TRIAL ->
            if IsTrial == CanTry ->
                    PriVal;
                true ->
                    calc_privilege_val(L, IsTrial)
            end;
        true ->
            PriVal
    end.


%----------------获取配置客服信息------------------%%
get_service_cfg(Source) ->
    IdList = data_customer_service:get_ids(),
    do_get_service_cfg(Source, IdList).

do_get_service_cfg(_, []) -> null;
do_get_service_cfg(Source, [H|T]) ->
    case data_customer_service:get_cfg(H) of
        #base_customer_service{medium = Source} = Cfg -> Cfg;
        _ -> do_get_service_cfg(Source, T)
    end.
%% 根据关键字获取
get_key_service_cfg(Source) ->
    IdList = data_customer_service:get_ids(),
    do_get_key_service_cfg(Source, IdList).

do_get_key_service_cfg(_, []) -> null;
do_get_key_service_cfg(Source, [H|T]) ->
    case data_customer_service:get_cfg(H) of
        #base_customer_service{keyword = ""} ->
            do_get_key_service_cfg(Source, T);
        #base_customer_service{keyword = KeyWord} = Cfg ->
            case re:run(Source, KeyWord) of
                nomatch -> do_get_key_service_cfg(Source, T);
                _ -> Cfg
            end;
        _ -> do_get_key_service_cfg(Source, T)
    end.

get_access_vip_lv_reward(RoleId, VipLv) ->
    VipLvs = lists:seq(1, VipLv),
    VipCounts = lib_counter:get_count(RoleId, ?MOD_VIP, 3, VipLvs),
    lists:foldl(fun({Lv, Count}, Acc) ->
        if Count =< 0 -> [Lv|Acc];
            true -> Acc
        end
    end, [], VipCounts).
