%% -----------------------------------------------------
%% @author  :ljy
%% moudle   :permit_login.erl
%% desc     :登录通行证
%% time     :2020.12.11
%% ------------------------------------------------------
-module(permit_login).


-include("server.hrl").
-include("custom_act.hrl").
-include("errcode.hrl").
-include("permit.hrl").
-include("figure.hrl").
-include("def_goods.hrl").
-include("def_module.hrl").
-include("pass_codex.hrl").
-include("def_fun.hrl").
-include("predefine.hrl").
-include("act_adventure.hrl").
-include("common.hrl").
-include("rec_event.hrl").
-include("def_event.hrl").

%% API
-export([
    permit_info/2
    , reward_info/2
    , handle_event/2
    , check/1
    , receive_reward/3
    , buy_ace_permit/2
    , register_login/3                        %% 补签
    , gm_add_login_day/3
]).


%% 获取宝典活动信息
permit_info(Player, SubType) ->
    #player_status{id = RoleId, sid = Sid} = Player,
    case lib_custom_act_util:get_custom_act_open_info(?CUSTOM_ACT_TYPE_PERMIT_LOGIN, SubType) of
        #act_info{} ->
            {_CustomData, ActData} = get_act_data(RoleId, SubType),
            {ok, BinData} = pack_permit_info(SubType, ActData),
            lib_server_send:send_to_sid(Sid, BinData),
            ok;
        _ ->
            {ok, BinData} = pt_332:write(33238, [?ERRCODE(err331_act_closed), SubType, 0, 0, 0, []]),
            lib_server_send:send_to_sid(Sid, BinData)
    end.

%% 打包宝典活动信息
pack_permit_info(SubType, ActData) ->
    #permit_login{
        login_list = LoginList,
        pay_permit = IsPay,
        normal_reward = NormalReward,
        pay_reward = PayReward
    } = ActData,
    ActType = ?CUSTOM_ACT_TYPE_PERMIT_LOGIN,
    GradeIds = data_pass_codex:get_act_lv(ActType, SubType),
    F = fun(GradeId, Acc) ->
        NeedDay = data_pass_codex:get_lv_exp(ActType, SubType, GradeId),
        IsLogin = lists:member(NeedDay, LoginList),
        if
            IsLogin ->
                NormalStatus =
                    case lists:member(GradeId, NormalReward) of
                        true -> ?REWARD_2;
                        _ -> ?REWARD_1
                    end,
                PayStatus =
                    case lists:member(GradeId, PayReward) of
                        true -> ?REWARD_2;
                        _ ->
                            if IsPay == 1 -> ?REWARD_1;
                                true -> ?REWARD_0
                            end
                    end,
                [{GradeId, NeedDay, NormalStatus, PayStatus} | Acc];
            true ->
                [{GradeId, 0, ?REWARD_0, ?REWARD_0} | Acc]
        end
        end,
    RewardInfo = lists:foldl(F, [], GradeIds),
    #act_info{stime = STime} = lib_custom_act_util:get_custom_act_open_info(ActType, SubType),
    Days = utime:day_span(STime),
    pt_332:write(33283, [?SUCCESS, ActType, SubType, Days, IsPay, RewardInfo]).

%% 奖励信息
reward_info(Player, SubType) ->
    #player_status{sid = Sid} = Player,
    ActType = ?CUSTOM_ACT_TYPE_PERMIT_LOGIN,
    case lib_custom_act_util:get_custom_act_open_info(ActType, SubType) of
        #act_info{key = {_, SubType}} ->
            {ok, BinData} = pack_reward_info(SubType),
            lib_server_send:send_to_sid(Sid, BinData);
        _ ->
            {ok, BinData} = pt_332:write(33286, [?ERRCODE(err331_act_closed), ActType, SubType, []]),
            lib_server_send:send_to_sid(Sid, BinData)
    end.

%% 打包奖励信息
pack_reward_info(SubType) ->
    ActType = ?CUSTOM_ACT_TYPE_PERMIT_LOGIN,
    GradeList = data_pass_codex:get_act_lv(ActType, SubType),
    F = fun(GradeId, {Acc, Success}) ->
        case data_pass_codex:get_reward_info(ActType, SubType, GradeId) of
            #base_pass_rewards{normal_rewards = NormalReward, lv_exp = NeedDay, trump_rewards = TrumpRewards, node_reward = NodeReward} ->
                {[{GradeId, NeedDay, util:term_to_string(NormalReward), util:term_to_string(TrumpRewards), NodeReward} | Acc], Success};
            _ -> {Acc, 0}
        end
        end,
    {RewardInfo, IsSuccess} = lists:foldl(F, {[], 1}, GradeList),
    if
        IsSuccess == 1 andalso RewardInfo =/= [] ->
            pt_332:write(33286, [?SUCCESS, ActType, SubType, RewardInfo]);
        true ->
            pt_332:write(33286, [?MISSING_CONFIG, ActType, SubType, []])
    end.

%% 0点事件
handle_event(Player, #event_callback{type_id = ?EVENT_ZERO_CLOCK}) ->
    SubTypeList = lib_custom_act_util:get_subtype_list(?CUSTOM_ACT_TYPE_PERMIT_LOGIN),
    [updata(Player#player_status.id, SubType) || SubType <- SubTypeList],
    {ok, Player};
%% 登录事件
handle_event(Player, #event_callback{type_id = ?EVENT_LOGIN_CAST}) ->
    SubTypeList = lib_custom_act_util:get_subtype_list(?CUSTOM_ACT_TYPE_PERMIT_LOGIN),
    [updata(Player#player_status.id, SubType) || SubType <- SubTypeList],
    {ok, Player}.

updata(RoleId, SubType) ->
    case lib_custom_act_util:get_custom_act_open_info(?CUSTOM_ACT_TYPE_PERMIT_LOGIN, SubType) of
        #act_info{} ->
            {CustomData, ActData} = get_act_data(RoleId, SubType),
            #permit_login{login_list = LoginList} = ActData,
            #act_info{stime = STime} = lib_custom_act_util:get_custom_act_open_info(?CUSTOM_ACT_TYPE_PERMIT_LOGIN, SubType),
            Days = utime:day_span(STime),
            case lists:member(Days, LoginList) of
                true -> skip;
                _ ->
                    NewActData = ActData#permit_login{login_list = [Days | LoginList]},
                    NewCustomData = CustomData#custom_act_data{act_data = NewActData},
                    lib_custom_act_data:save_custom_data(RoleId, NewCustomData),
                    {ok, BinData} = pack_permit_info(SubType, NewActData),
                    lib_server_send:send_to_uid(RoleId, BinData)
            end;
        _ -> skip
    end.


%% 获取活动数据
get_act_data(RoleId, SubType) ->
    #custom_act_data{
        act_data = ActData
    } = CustomData = lib_custom_act_data:custom_act_data(?CUSTOM_ACT_TYPE_PERMIT_LOGIN, SubType),
    NewActData =
        case ActData of
            #permit_login{} ->
                ActData;
            _ ->
                #permit_login{}
        end,
    if
        NewActData =/= ActData ->
            NewCustomData = CustomData#custom_act_data{act_data = NewActData},
            lib_custom_act_data:save_custom_data(RoleId, NewCustomData);
        true ->
            NewCustomData = CustomData
    end,
    {NewCustomData, NewActData}.

%% 购买王牌宝典
buy_ace_permit(Player, SubType) ->
    #player_status{id = RoleId, sid = Sid, figure = Figure} = Player,
    #figure{lv = Lv} = Figure,
    case get_role_permit(RoleId, SubType) of
        {true, #act_info{key = {_, SubType}}, ActData} ->
            CheckL = [
                {act_is_open, SubType, Lv},
                {buy_cost_check, Player, ?CUSTOM_ACT_TYPE_PERMIT_LOGIN, SubType},
                {payed_check, ActData}
            ],
            case util:check_lists(permit_login, CheckL) of
                true ->
                    do_buy_ace_permit(Player, SubType);
                {false, Errcode} ->
                    {ok, BinData} = pt_332:write(33285, [Errcode, ?CUSTOM_ACT_TYPE_PERMIT_LOGIN, SubType]),
                    lib_server_send:send_to_sid(Sid, BinData)
            end;
        {false, Errcode} ->
            {ok, BinData} = pt_332:write(33285, [Errcode, ?CUSTOM_ACT_TYPE_PERMIT_LOGIN, SubType]),
            lib_server_send:send_to_sid(Sid, BinData)
    end.

%% 获取玩家活动数据
get_role_permit(RoleId, SubType) ->
    case lib_custom_act_util:get_custom_act_open_info(?CUSTOM_ACT_TYPE_PERMIT_LOGIN, SubType) of
        ActInfo = #act_info{key = {_, SubType}} ->
            {_CustomData, ActData} = get_act_data(RoleId, SubType),
            {true, ActInfo, ActData};
        _ ->
            {false, ?ERRCODE(err331_act_closed)}
    end.

do_buy_ace_permit(Player, SubType) ->
    #player_status{id = RoleId, sid = Sid} = Player,
    ActType = ?CUSTOM_ACT_TYPE_PERMIT_LOGIN,
    #custom_act_cfg{condition = Condition} = lib_custom_act_util:get_act_cfg_info(ActType, SubType),
    {limit_cost, Price} = lists:keyfind(limit_cost, 1, Condition),
    Cost = [{?TYPE_GOLD, 0, Price}],
    case lib_goods_api:cost_object_list_with_check(Player, Cost, permit_login_cost, "") of
        {true, NewPlayer, _} ->
            {CustomData, ActData} = get_act_data(RoleId, SubType),
            NewActData = ActData#permit_login{pay_permit = 1},
            lib_custom_act_data:save_custom_data(RoleId, CustomData#custom_act_data{act_data = NewActData}),
            {ok, BinData} = pt_332:write(33285, [?SUCCESS, ActType, SubType]),
            {ok, BinData2} = pack_permit_info(SubType, NewActData),
            lib_server_send:send_to_sid(Sid, <<BinData/binary, BinData2/binary>>),
            lib_log_api:custom_act_reward_log(NewPlayer, Player, ?CUSTOM_ACT_TYPE_PERMIT_LOGIN, SubType, 0, util:term_to_bitstring([buy,[]]), []),
            {ok, NewPlayer};
        {false, Errcode, _} ->
            {ok, BinData} = pt_332:write(33285, [Errcode, SubType]),
            lib_server_send:send_to_sid(Sid, BinData)
    end.


%% 领取等级奖励
receive_reward(Player, GradeId, SubType) ->
    #player_status{id = RoleId, sid = Sid, figure = #figure{lv = Lv}} = Player,
    CheckL = [
        {act_is_open, SubType, Lv},
        {receive_check, GradeId, RoleId, SubType}
    ],
    case util:check_lists(?MODULE, CheckL) of
        true ->
            {CustomActData, ActData} = get_act_data(RoleId, SubType),
            {RewardList, RewardType} = calc_reward(RoleId, SubType, CustomActData, ActData, GradeId, save),
            if
                RewardType == 0 ->
                    NewPlayer = Player,
                    {ok, BinData} = pt_332:write(33287, [?ERRCODE(err331_have_contract_reward), SubType, GradeId, RewardType]);
                true ->
                    NewPlayer = lib_goods_api:send_reward(Player, RewardList, permit_login_reward),
                    lib_log_api:custom_act_reward_log(NewPlayer, Player, ?CUSTOM_ACT_TYPE_PERMIT_LOGIN, SubType, 0, util:term_to_bitstring([{GradeId, RewardType}]), RewardList),
                    {ok, BinData} = pt_332:write(33287, [?SUCCESS, SubType, GradeId, RewardType])
            end,
            lib_server_send:send_to_sid(Sid, BinData),
            {ok, NewPlayer};
        {false, ErrCode} ->
            {ok, BinData} = pt_332:write(33284, [ErrCode, SubType, []]),
            lib_server_send:send_to_sid(Sid, BinData)
    end.

%% 计算奖励
calc_reward(RoleId, SubType, CustomActData, ActData, GradeId, Type) ->
    #permit_login{
        normal_reward = NormalReward,
        pay_reward = PayReward,
        pay_permit = IsPay,
        login_list = LoginList
    } = ActData,
    ActType = ?CUSTOM_ACT_TYPE_PERMIT_LOGIN,
    case data_pass_codex:get_reward_info(ActType, SubType, GradeId) of
        #base_pass_rewards{lv_exp = NeedDay, normal_rewards = Reward1, trump_rewards = Reward2} ->
            IsNormalReward = lists:member(GradeId, NormalReward),
            IsPayReward = (IsPay == 1 andalso (not lists:member(GradeId, PayReward))),
            IsLogin = lists:member(NeedDay, LoginList),
            {RewardList, RewardType} =
                if
                    not IsLogin ->
                        NewActData = ActData,
                        {[], 0};
                    (not IsNormalReward) andalso IsPayReward ->
                        NewActData = ActData#permit_login{normal_reward = [GradeId | NormalReward], pay_reward = [GradeId | PayReward]},
                        {Reward1 ++ Reward2, 3};
                    not IsNormalReward ->
                        NewActData = ActData#permit_login{normal_reward = [GradeId | NormalReward]},
                        {Reward1, 1};
                    IsPayReward ->
                        NewActData = ActData#permit_login{pay_reward = [GradeId | PayReward]},
                        {Reward2, 2};
                    true ->
                        NewActData = ActData,
                        {[], 0}
                end,
            if
                RewardList =:= [] -> skip;
                Type =:= false -> skip;
                true ->
                    lib_custom_act_data:save_custom_data(RoleId, CustomActData#custom_act_data{act_data = NewActData})
            end,
            {RewardList, RewardType};
        _ ->
            {[], 0}
    end.

%% 补签
register_login(Player, GradeId, SubType) ->
    ActType = ?CUSTOM_ACT_TYPE_PERMIT_LOGIN,
    #player_status{id = RoleId, figure = Figure} = Player,
    #figure{lv = Lv} = Figure,
    CheckL = [
        {act_is_open, SubType, Lv},
        {register_cost_check, Player, ActType, SubType},
        {data_check, ActType, SubType, GradeId}
    ],
    case util:check_lists(?MODULE, CheckL) of
        true ->
            #player_status{id = RoleId} = Player,
            {CustomData, ActData} = get_act_data(RoleId, SubType),
            #permit_login{
                login_list = LoginList,
                pay_permit = IsPay,
                normal_reward = NormalReward,
                pay_reward = PayReward
            } = ActData,
            NeedDay = data_pass_codex:get_lv_exp(ActType, SubType, GradeId),
            IsLogin = lists:member(NeedDay, LoginList),
            IsNormalRewarded = lists:member(GradeId, NormalReward),
            IsPayReward = lists:member(GradeId, PayReward),
            #custom_act_cfg{condition = Condition} = lib_custom_act_util:get_act_cfg_info(ActType, SubType),
            {extra_sign, Cost} = lists:keyfind(extra_sign, 1, Condition),
            if
                IsLogin -> {false, ?ERRCODE(err331_lucky_flop_reward_repeat)};
                IsNormalRewarded andalso IsPayReward -> {false, ?ERRCODE(reward_is_got)};
                IsNormalRewarded andalso (not IsPayReward) andalso IsPay == 0 -> {false, ?ERRCODE(err331_not_buy)};
                true ->
                    case lib_goods_api:cost_object_list_with_check(Player, Cost, permit_login_cost, "") of
                        {true, NewPlayer, _} ->
                            NeedDay = data_pass_codex:get_lv_exp(ActType, SubType, GradeId),
                            do_register_login(NewPlayer, RoleId, SubType, CustomData, ActData#permit_login{login_list = [NeedDay | LoginList]}, GradeId);
                        {false, Errcode, _} ->
                            {false, Errcode}
                    end
            end;
        {false, Errcode} ->
            {false, Errcode}
    end.

do_register_login(Player, RoleId, SubType, CustomData, ActData, GradeId) ->
    #player_status{id = RoleId, sid = Sid} = Player,
    {RewardList, RewardType} = calc_reward(RoleId, SubType, CustomData, ActData, GradeId, save),
    NewPlayer = lib_goods_api:send_reward(Player, RewardList, permit_login_reward),
    {ok, BinData} = pt_332:write(33288, [?SUCCESS, SubType, GradeId, RewardType]),
    lib_server_send:send_to_sid(Sid, BinData),
    lib_log_api:custom_act_reward_log(NewPlayer, Player, ?CUSTOM_ACT_TYPE_PERMIT_LOGIN, SubType, 0, util:term_to_bitstring([{GradeId, RewardType}]), RewardList),
    {ok, NewPlayer}.

check({act_is_open, SubType, RoleLv}) ->
    ActType = ?CUSTOM_ACT_TYPE_PERMIT_LOGIN,
    case lib_custom_act_util:get_custom_act_open_info(ActType, SubType) of
        #act_info{} ->
            case lib_custom_act_util:get_act_cfg_info(ActType, SubType) of
                #custom_act_cfg{condition = Condition} ->
                    case lists:keyfind(lv, 1, Condition) of
                        {lv, Lv} -> skip;
                        _ -> Lv = -1
                    end,
                    if
                        Lv =:= -1 ->
                            {false, ?ERRCODE(config_err)};
                        RoleLv < Lv ->
                            {false, ?ERRCODE(lv_limit)};
                        true ->
                            true
                    end;
                _ ->
                    {false, ?ERRCODE(config_err)}
            end;
        _ ->
            {false, ?ERRCODE(err331_act_closed)}
    end;
check({data_check, ActType, SubType, GradeId}) ->
    #act_info{stime = STime} = lib_custom_act_util:get_custom_act_open_info(ActType, SubType),
    Days = utime:day_span(STime),
    case data_pass_codex:get_lv_exp(ActType, SubType, GradeId) of
        [] -> {false, ?ERRCODE(missing_config)};
        CfgDay when CfgDay >= Days -> {false, ?ERRCODE(fail)};
        _CfgDay -> true
    end;
check({receive_check, GradeId, RoleId, SubType}) ->
    ActType = ?CUSTOM_ACT_TYPE_PERMIT_LOGIN,
    {_CustomData, ActData} = get_act_data(RoleId, SubType),
    #permit_login{
        login_list = LoginList,
        pay_permit = IsPay,
        normal_reward = NormalReward,
        pay_reward = PayReward
    } = ActData,
    NeedDay = data_pass_codex:get_lv_exp(ActType, SubType, GradeId),
    IsLogin = lists:member(NeedDay, LoginList),
    if
        IsLogin ->
            IsNormalRewarded = lists:member(GradeId, NormalReward),
            IsPayReward = lists:member(GradeId, PayReward),
            if (not IsNormalRewarded) orelse (IsPay =/= 0 andalso (not IsPayReward)) ->
                true;
                true ->
                    {false, ?ERRCODE(reward_is_got)}
            end;
        true ->
            {false, ?ERRCODE(err331_can_not_pick_up)}
    end;
check({buy_cost_check, Player, ActType, SubType}) ->
    case lib_custom_act_util:get_act_cfg_info(ActType, SubType) of
        #custom_act_cfg{condition = Condition} ->
            case lists:keyfind(limit_cost, 1, Condition) of
                {limit_cost, Price} -> skip;
                _ -> Price = -1
            end,
            if
                Price >= 0 ->
                    lib_goods_api:check_object_list(Player, [{?TYPE_GOLD, 0, Price}]);
                true ->
                    {false, ?ERRCODE(config_err)}
            end;
        _ ->
            {false, ?ERRCODE(config_err)}
    end;
check({register_cost_check, Player, ActType, SubType}) ->
    case lib_custom_act_util:get_act_cfg_info(ActType, SubType) of
        #custom_act_cfg{condition = Condition} ->
            case lists:keyfind(extra_sign, 1, Condition) of
                {extra_sign, Cost} -> skip;
                _ -> Cost = []
            end,
            if
                Cost =:= [] ->
                    {false, ?ERRCODE(config_err)};
                true ->
                    lib_goods_api:check_object_list(Player, Cost)
            end;
        _ ->
            {false, ?ERRCODE(config_err)}
    end;
check({payed_check, ActData}) ->
    #permit_login{pay_permit = IsPay} = ActData,
    if
        IsPay =/= 0 ->
            {false, ?ERRCODE(err331_contract_haved_buy)};
        true ->
            true
    end;
check(_A) ->
    {false, ?FAIL}.

%%--------------------------gm--------------------------------
%% 增加登录天数
gm_add_login_day(Player, SubType, Day) ->
    #player_status{id = RoleId} = Player,
    case lib_custom_act_util:get_custom_act_open_info(?CUSTOM_ACT_TYPE_PERMIT_LOGIN, SubType) of
        #act_info{} ->
            {CustomData, ActData} = get_act_data(RoleId, SubType),
            #permit_login{login_list = LoginList} = ActData,
            NewActData = ActData#permit_login{login_list = [Day | LoginList]},
            NewCustomData = CustomData#custom_act_data{act_data = NewActData},
            lib_custom_act_data:save_custom_data(RoleId, NewCustomData);
        _ ->
            skip
    end.

