%%%-------------------------------------------------------------------
%%% @author liushl
%%% @doc
%%%     福利大厅
%%% @end
%%%-------------------------------------------------------------------
-module(welfare_api).
-author("liushl").

-include("def_module.hrl").
-include("welfare.hrl").
-include("server.hrl").
-include("errcode.hrl").
-include("goods.hrl").
-include("def_event.hrl").
-include("rec_event.hrl").
-include("figure.hrl").
-include("role_foster.hrl").
-include("def_goods.hrl").
-include("common.hrl").
-include("server_kv.hrl").
%% API
-export([
    login/1,                        %% 登陆初始化
    handle_event/2,                 %% 事件处理
    welfare_sign_in/1,              %% 领取签到奖励
    get_cumulative_sign_in_award/2, %% 领取累计签到奖励
    get_welfare_level_award/2,      %% 领取冲级大礼
    get_newbee_info/1,              %% 新手引导领奖查询
    get_welfare_online_award/2,     %% 领取在线奖励
    get_now_online_time/1,          %% 获得当前在线时长
    re_calc_online_time/1,
    get_welfare_download_award/1    %% 资源下载礼包
]).

%% 登陆初始化
login(RoleId) ->
    case db:get_row(?SQL_GET_WELFARE_DATA, [RoleId]) of
        [Round, Days, OnlineType, LevelAwardState, DownloadAwardState, CumulativeInfo] ->
            #status_welfare{
                sign_in_round = Round
                , sign_in_days = Days
                , online_type = OnlineType
                , level_award_state = LevelAwardState
                , download_award_state = DownloadAwardState
                , cumulative_sign_in_info = CumulativeInfo
            };
        _ ->
            #status_welfare{}
    end.

%% @doc 事件处理
%% 上线处理：初始化每日签到周期/重新计算在线奖励类型
handle_event(Player, #event_callback{type_id = ?EVENT_LOGIN_CAST}) ->
    #player_status{id = RoleId} = Player,
    %% 如果当天没有签到，那就判断是否进入下一轮签到
    Status = lib_daily:get_count(RoleId, ?MOD_WELFARE, ?COUNTER_WELFARE_SIGN_IN),
    case Status of
        0  ->
            Player1 = check_new_round(Player);
        _  ->
            Player1 = Player
    end,
    %% 重新计算在线类型
    Player2 = re_calc_online_type(Player1),

    {ok, Player2};

%% 0点处理：进入下一轮每日签到/重新计算在线奖励类型
handle_event(Player, #event_callback{type_id = ?EVENT_ZERO_CLOCK}) ->
    Player1 = check_new_round(Player),
    Player2 = re_calc_online_type(Player1),
    pp_welfare:handle(16001, Player2, []),
    pp_welfare:handle(16003, Player2, []),
    {ok, Player2};

%% 离线处理
handle_event(Player, #event_callback{type_id = ?EVENT_DISCONNECT}) ->
    %% 托管玩家不处理
    Player#player_status.online =/= ?ONLINE_OFF_HOSTING andalso
        re_calc_online_time(Player),
    {ok, Player};

handle_event(Player, _) ->
    {ok, Player}.
%%%-------------------------------------------------------------------
%%% @doc 每日签到 Status: 0未签到|1签到
%%%-------------------------------------------------------------------
welfare_sign_in_check(Player) ->
    #player_status{id = RoleId, welfare = Welfare, figure = #figure{vip = VipLv}} = Player,
    #status_welfare{sign_in_round = Round, sign_in_days = Days} = Welfare,
    Status = lib_daily:get_count(RoleId, ?MOD_WELFARE, ?COUNTER_WELFARE_SIGN_IN),
    %% 决定读配置用哪个参数
    ConfigDays = case Status of
                     0 -> Days + 1;
                     _ -> Days
                 end,
    case data_welfare:get_welfare_sign_in_award(Round, ConfigDays) of
        #base_welfare_sign_in_award{
            award = Award,
            vip_lv = VipNeed
        } ->
            case Status of
                0 -> %% 第一次领取
                    NewDays = Days+1,
                    case VipNeed > 0 of
                        true  -> %% 今天可以VIP翻倍
                            {true, Award, NewDays, 1, 0};
                        false -> %% 今天所有人都只能领一份
                            {true, Award, NewDays, 2, 0}
                    end;
                1 -> %% 已经领过一次了，只有配置了VIP加倍的天数可以再领一份
                    case VipNeed > 0 andalso VipLv >= VipNeed of
                        true  ->
                            {true, Award, Days, 2, VipNeed};
                        false ->
                            {false, ?ERRCODE(err160_sign_in_vip)}
                    end;
                2 ->
                    {false, ?ERRCODE(err160_sign_in_over)};
                _ ->
                    {false, 0}
            end;
        _ ->
            {false, ?MISSING_CONFIG}
    end.
%% 领取签到奖励
welfare_sign_in(Player) ->
    case welfare_sign_in_check(Player) of
        {false, Err} -> {false, Err};
        {true, Award, NewDays, State, VipNeed} ->
            #player_status{id = RoleId, welfare = Welfare, figure = Figure} = Player,
            lib_daily:set_count(RoleId, ?MOD_WELFARE, ?COUNTER_WELFARE_SIGN_IN, State),
            NewWelfare = Welfare#status_welfare{sign_in_days = NewDays},
            db_save_welfare(RoleId, NewWelfare),
            Produce = #produce{
                reward = Award,
                type = welfare_sign_in,
                remark = lists:concat(["round=", Welfare#status_welfare.sign_in_round, ", days=", NewDays])
            },
            Player1 = lib_goods_api:send_reward(Player#player_status{welfare = NewWelfare}, Produce),
            lib_log_api:log_sign_in(
                [RoleId, Figure#figure.name, Figure#figure.lv, Welfare#status_welfare.sign_in_round,
                    NewDays, util:term_to_bitstring(Award), VipNeed, Figure#figure.vip, utime:unixtime()]
            ),
            {ok, Player1}
    end.

%% 判断是否开始新的一轮签到
check_new_round(Player) ->
    #player_status{id = RoleId, welfare = Welfare, figure = #figure{lv = Lv}} = Player,
    #status_welfare{
        sign_in_round = OldRound,
        sign_in_days = Days
    } = Welfare,
    NewWelfare = case Days =:= 30 orelse OldRound =:= 0 of
         true  ->
             Round = data_welfare:get_welfare_sign_in_round(Lv),
             case Round > 0 of
                 true  ->
                     Welfare1 = Welfare#status_welfare{sign_in_round = Round, sign_in_days = 0, cumulative_sign_in_info = 0},
                     MaxRound = data_welfare:get_welfare_sign_in_max_round(),
                     %% 当前已经是配置的最大轮次了，之后不会变化轮次，所以没必要实时保存，之后签到会保存的, 就算没有进行保存，再次登陆会重新执行一遍该方法
                     Round =/= MaxRound andalso
                        db_save_welfare(RoleId, Welfare1),
                     Welfare1;
                 false ->
                     ?ERR("welfare_sign_in_round no cfg when lv=~p", [Lv]),
                     Welfare
             end;
         false ->
             Welfare
     end,
    Player#player_status{welfare = NewWelfare}.

%% 领取累计签到奖励
get_cumulative_sign_in_award_check(Player, No) ->
    #player_status{welfare = Welfare} = Player,
    #status_welfare{
        sign_in_round = Round,
        sign_in_days = Days,
        cumulative_sign_in_info = CumulativeInfo
    } = Welfare,
    AwardCfg = data_welfare:get_welfare_cumulative_sign_in_award(Round),
    IsGet = ?WELFARE_AWARD_STATE(CumulativeInfo, No),
    case lists:keyfind(No, 1, AwardCfg) of
        {_, NeedDays, Award} ->
            if
                No > 15 -> {false, 0};
                NeedDays > Days -> {false, ?ERRCODE(err160_condition_error)};
                IsGet > 0 -> {false, ?ERRCODE(err160_repeat_get)};
                Award =:= [] orelse (not is_list(Award)) -> {false, ?MISSING_CONFIG};
                true ->
                    NewCumulativeInfo = ?WELFARE_SET_AWARD_STATE(CumulativeInfo, No),
                    {true, Award, NewCumulativeInfo}
            end;
        _ ->
            {false, ?MISSING_CONFIG}
    end.

get_cumulative_sign_in_award(Player, No) ->
    case get_cumulative_sign_in_award_check(Player, No) of
        {false, Err} -> {false, Err};
        {true, Award, NewCumulativeInfo} ->
            #player_status{id = RoleId, welfare = Welfare} = Player,
            NewWelfare = Welfare#status_welfare{cumulative_sign_in_info = NewCumulativeInfo},
            db_save_welfare(RoleId, NewWelfare),
            Produce = #produce{
                reward = Award,
                type = welfare_cumulative_sign_in,
                remark = lists:concat(["no=", No])
            },
            Player1 = lib_goods_api:send_reward(Player#player_status{welfare = NewWelfare}, Produce),
            {ok, Player1}
    end.
%%%-------------------------------------------------------------------
%%% @doc 冲级大礼:目前只支持63位
%%%-------------------------------------------------------------------
get_welfare_level_award_check(Player, No) ->
    #player_status{
        welfare = #status_welfare{level_award_state = AwardState},
        figure = #figure{lv = Lv, career = Career}
    } = Player,
    Config = data_welfare:get_welfare_level_award(Career, No),

    IsGet = ?WELFARE_AWARD_STATE(AwardState, No),
    if
        No > 63 -> {false, 0};
        not is_record(Config, base_welfare_level_award) ->
            {false, ?MISSING_CONFIG};
        IsGet > 0 ->
            {false, ?ERRCODE(err160_repeat_get)};
        true ->
            #base_welfare_level_award{
                level = NeedLevel,
                award = Award,
                limit_award = LimitAward,
                limit_num = LimitNum
            } = Config,
            case Lv < NeedLevel of
                true  ->
                    {false, ?ERRCODE(err160_level_low)};
                false ->
                    ExtraAward =
                        case LimitNum > 0 of
                            true  ->
                                Num = mod_global_counter:get_count(?MOD_WELFARE, ?COUNTER_GLOBAL_LEVEL_AWARD, No),
                                LeftNum = max(LimitNum - Num - 1, 0),
                                case Num >= LimitNum of
                                    true  -> [];
                                    false -> LimitAward
                                end;
                            false ->
                                LeftNum = 0,
                                []
                        end,
                    NewAwardState = ?WELFARE_SET_AWARD_STATE(AwardState, No),
                    {true, Award, ExtraAward, NewAwardState, NeedLevel, LeftNum}
            end
    end.
%% 领取冲级大礼
get_welfare_level_award(Player, No) ->
    case get_welfare_level_award_check(Player, No) of
        {false, Err} -> {false, Err};
        {true, Award, ExtraAward, NewAwardState, NeedLevel, Num} ->
            #player_status{welfare = Welfare, id = RoleId, figure = Figure} = Player,
            %% 领取了限定奖励，则全服计数器+1
            update_level_award_log(RoleId, No),
            ExtraAward =/= [] andalso mod_global_counter:increment(?MOD_WELFARE, ?COUNTER_GLOBAL_LEVEL_AWARD, No),
            NewWelfare = Welfare#status_welfare{level_award_state = NewAwardState},
            db_save_welfare(RoleId, NewWelfare),
            Player1 = lib_goods_api:send_reward(Player#player_status{welfare = NewWelfare}, ExtraAward ++ Award, welfare_level_award, No),
            lib_log_api:log_level_award(
                [RoleId, Figure#figure.name, Figure#figure.lv, Figure#figure.career, No, NeedLevel,
                    util:term_to_bitstring(Award), util:term_to_bitstring(ExtraAward), Num, utime:unixtime()]
            ),
            {ok, Player1}
    end.

update_level_award_log(RoleId, 1) ->
    [{_, AwardLog}] = lib_server_kv:get_value([{?SERVER_KV_LEVEL_AWARD_LOG, []}]),
    lib_server_kv:update_server_kv_ets(
        #server_kv{key = ?SERVER_KV_LEVEL_AWARD_LOG, value = lists:sublist([RoleId|AwardLog], 5)}
    );
update_level_award_log(_, _) -> ok.

%% 新手引导领奖查询
get_newbee_info(_Player) ->
    Count = mod_global_counter:get_count(?MOD_WELFARE, ?COUNTER_GLOBAL_LEVEL_AWARD, 1),
    [{_, AwardLog}] = lib_server_kv:get_value([{?SERVER_KV_LEVEL_AWARD_LOG, []}]),
    [
        Count,
        [
            lib_role:get_role_figure(Id)||Id <- AwardLog
        ]
    ].
%%%-------------------------------------------------------------------
%%% @doc 在线奖励
%%%-------------------------------------------------------------------
get_welfare_online_award_check(Player, No) ->
    #player_status{id = RoleId, welfare = Welfare} = Player,
    #status_welfare{online_type = OnlineType} = Welfare,
    AwardState = lib_daily:get_count(RoleId, ?MOD_WELFARE, ?COUNTER_WELFARE_ONLINE_AWARD),
    Config = data_welfare:get_welfare_online_award(OnlineType, No),
    IsGet = ?WELFARE_AWARD_STATE(AwardState, No),
    if
        Config =:= [] ->
            {false, ?MISSING_CONFIG};
        IsGet > 0 ->
            {false, ?ERRCODE(err160_repeat_get)};
        true ->
            {NeedTime, Award} = Config,
            NowOnlineTime = get_now_online_time(Player),
            case NowOnlineTime < NeedTime of
                true  ->
                    {false, ?ERRCODE(err160_online_time_less)};
                false ->
                    NewAwardState = ?WELFARE_SET_AWARD_STATE(AwardState, No),
                    {true, Award, NewAwardState}
            end
    end.
%% 领取在线奖励
get_welfare_online_award(Player, No) ->
    case get_welfare_online_award_check(Player, No) of
        {false, Err} -> {false, Err};
        {true, Award, NewAwardState} ->
            lib_daily:set_count(Player#player_status.id, ?MOD_WELFARE, ?COUNTER_WELFARE_ONLINE_AWARD, NewAwardState),
            Player1 = lib_goods_api:send_reward(Player, Award, welfare_online_award, No),
            {ok, Player1}
    end.

%% 重新统计在线时长:下线统计
re_calc_online_time(Player) ->
    #player_status{
        id = RoleId
    } = Player,
    Time = get_now_online_time(Player),
    Time > 0 andalso
        lib_daily:set_count(RoleId, ?MOD_WELFARE, ?COUNTER_WELFARE_ONLINE_TIME, Time).

%% 获得当前在线时长
get_now_online_time(Player) ->
    #player_status{
        id = RoleId,
        last_login_time = LoginTime
    } = Player,
    Midnight = utime:unixdate(),
    Now = utime:unixtime(),
    BaseTime = lib_daily:get_count(RoleId, ?MOD_WELFARE, ?COUNTER_WELFARE_ONLINE_TIME),
    max(
        (Now - max(LoginTime, Midnight)) + BaseTime, 0
    ).

%% 重新计算在线奖励类型
re_calc_online_type(Player) ->
    #player_status{id = _RoleId, welfare = Welfare} = Player,
    #status_welfare{online_type = OldType} = Welfare,
    NowType = get_now_online_type(Player),
    case OldType =:= NowType of
        true  ->
            Player;
        false ->
            NewWelfare = Welfare#status_welfare{online_type = NowType},
            Player#player_status{welfare = NewWelfare}
    end.

%% 当前应当用哪个奖励类型:拿到超过30个碎片或者激活了对应皮肤就进入第2轮
%% 当前类型已经是2了，无须判断是否进入2
get_now_online_type(#player_status{welfare = #status_welfare{online_type = 2}}) -> 2;
get_now_online_type(Player) ->
    AiFigure = 2,
    AiChipId = 405001,
    case lib_role_foster_skin:is_active_ai_skin(Player, AiFigure) of
        true  ->
            %% 激活了珍宝，转为2
            2;
        false ->
            GoodsStatus = lib_goods_do:get_goods_status(),
            InBag       = lib_goods_util:get_type_goods_list(AiChipId, ?GOODS_LOC_BAG, GoodsStatus#goods_status.dict),
            InStorage   = lib_goods_util:get_type_goods_list(AiChipId, ?GOODS_LOC_STORAGE, GoodsStatus#goods_status.dict),
            TotalNum    = lib_goods_util:get_goods_total_num(InStorage ++ InBag),
            %% 身上有30个碎片了，也转为2
            case TotalNum >= 30 of
                true  -> 2;
                false -> 1
            end
    end.
%%%-------------------------------------------------------------------
%%% @doc 资源下载礼包
%%%-------------------------------------------------------------------
get_welfare_download_award(Player) ->
    #player_status{welfare = Welfare, id = RoleId} = Player,
    #status_welfare{download_award_state = AwardState} = Welfare,
    Award = data_welfare:get_welfare_kv(download_award),
    if
        not is_list(Award) -> {false, ?MISSING_CONFIG};
        AwardState > 0 -> {false, ?ERRCODE(err160_repeat_get)};
        true ->
            NewWelfare = Welfare#status_welfare{download_award_state = 1},
            db_save_welfare(RoleId, NewWelfare),
            Player1 = lib_goods_api:send_reward(Player#player_status{welfare = NewWelfare}, Award, welfare_download_award),
            {ok, Player1}
    end.

%%%-------------------------------------------------------------------
%%% @doc DB
%%%-------------------------------------------------------------------
db_save_welfare(RoleId, Welfare) ->
    #status_welfare{
        sign_in_round = Round,
        sign_in_days = Days,
        online_type = OnlineType,
        level_award_state = LevelAward,
        download_award_state = DownloadAward,
        cumulative_sign_in_info = CumulativeInfo
    } = Welfare,
    db:execute(?SQL_SAVE_WELFARE_DATA, [RoleId, Round, Days, OnlineType, LevelAward, DownloadAward, CumulativeInfo]).