%%-----------------------------------------------------------------------------
%% @Module  :       lib_recharge_cumulation.erl
%% @Author  :       J
%% @Email   :       j-som@foxmail.com
%% @Created :       2018-01-17
%% @Description:    累充活动
%%-----------------------------------------------------------------------------

-module (lib_recharge_cumulation).
-include ("def_event.hrl").
-include ("rec_event.hrl").
-include ("custom_act.hrl").
-include ("server.hrl").
-include ("common.hrl").
-include ("recharge_act.hrl").
-include ("errcode.hrl").
-include ("def_module.hrl").
-include ("figure.hrl").
-include ("goods.hrl").

-export ([
    handle_recharge_act/2
    ,login/1
    ,receive_reward/3
    ,get_reward_state/3
    ,update/1
]).

%% ------------------------------------
%  每日累充（act_type=6） by YanWeiFan
%  奖励由两个部分组成，一部分为当天累计充值奖励，每日刷新，会将上一天未领取的可领奖励发送邮箱
%  另一个部分为一个循环的累计N天充值M元奖励，一天内充值满M元则累计一次奖励可领取，这N天不需要连续、
%  重置时间依靠奖励领取条件中的cycle来确定，当某一天充值触发了拥有cycle条件的奖励可领取时，
%  第二天则会重置奖励，未领取奖励则邮件发送
%% ------------------------------------

login(Player) ->
    #player_status{id = RoleId} = Player,
    SQL = io_lib:format("SELECT `subtype`, `id`, `time`, `state`, `info` FROM `recharge_cumulation_reward` WHERE `player_id` = ~p", [RoleId]),
    All = db:get_all(SQL),
    CycleTimeList = %% 从计数器中读取上一个轮回的时间
        case lib_custom_act_util:get_subtype_list(?CUSTOM_ACT_TYPE_DAILY_CHARGE_CYCLE) of
            [] -> [];
            SubTypeList -> lib_counter:get_count_offline(RoleId, ?MOD_RECHARGE_ACT, ?MOD_RECHARGE_ACT_CUMULATION, SubTypeList)
        end,
    Cumulation0 = lists:foldl(fun
        ({SubType, Time}, Map) when Time > 0 ->
            Map#{{cycle_time, SubType} => Time};
        (_, Map) -> Map
    end, #{}, CycleTimeList),
    ZeroTime = utime:unixdate(), %% 获取当天0点的时间戳
    {Cumulation, ForgotList, InvailableList} = init_data(Cumulation0, All, ZeroTime, [], []),
    send_forgot_rewards(RoleId, ForgotList), %% 邮件返还未领取的奖励
    delete_forgot_list(RoleId, ForgotList ++ InvailableList), %% 删除过期的奖励列表
    Player#player_status{cumulative_charge = Cumulation}.


%% 返回当前的累充数据、忘记领取奖励但已经失效的数据、已经领奖并且已经失效的数据
init_data(Cumulation, [[SubType, Id, Time, State, InfoStr]|All], ZeroTime, ForgotList, InvailableList) ->
    case lib_custom_act_util:get_act_reward_cfg_info(?CUSTOM_ACT_TYPE_DAILY_CHARGE_CYCLE, SubType, Id) of
        #custom_act_reward_cfg{condition = Condition} ->
            Info = util:bitstring_to_term(InfoStr),
            case lists:keyfind(type, 1, Condition) of
                {type, 1} -> %% type1为每日领取
                    if
                        Time < ZeroTime -> %% 达成时间早于今日零点表示已经过时
                            if
                                State =:= 0 -> %% 还没领奖
                                    init_data(Cumulation, All, ZeroTime, [[SubType, Id, Info, Time]|ForgotList], InvailableList);
                                true -> %% 已经领奖
                                    init_data(Cumulation, All, ZeroTime, ForgotList, [[SubType, Id]|InvailableList])
                            end;
                        true -> %% 未过期
                            NewCumulation = Cumulation#{{reward, SubType, Id} => {Time, State, Info}},
                            init_data(NewCumulation, All, ZeroTime, ForgotList, InvailableList)
                    end;
                {type, 2} -> %% 周期领取 两次触发最后一个类型为2的奖励之间为1周期
                    CycleTime = maps:get({cycle_time, SubType}, Cumulation, 0),
                    if
                        CycleTime > 0 andalso Time < CycleTime -> %% 已经有周期 并且已经过期
                            if
                                State =:= 0 -> %% 还没领取
                                    init_data(Cumulation, All, ZeroTime, [[SubType, Id, Info, Time]|ForgotList], InvailableList);
                                true -> %% 已经领取
                                    init_data(Cumulation, All, ZeroTime, ForgotList, [[SubType, Id]|InvailableList])
                            end;
                        true -> %% 还没过期
                            NewCumulation = Cumulation#{{reward, SubType, Id} => {Time, State, Info}},
                            init_data(NewCumulation, All, ZeroTime, ForgotList, InvailableList)
                    end;
                _ -> %% 没有活动的配置 当作是失效的
                    init_data(Cumulation, All, ZeroTime, ForgotList, [[SubType, Id]|InvailableList])
            end;
        _ -> %% 没有活动的配置 当作是失效的
            init_data(Cumulation, All, ZeroTime, ForgotList, [[SubType, Id]|InvailableList])
    end;
init_data(Cumulation, [], _ZeroTime, ForgotList, InvailableList) -> {Cumulation, ForgotList, InvailableList}.

%% 在线跨天/充值，更新客户端数据
update(#player_status{online = ?ONLINE_ON} = Player) ->
    case lib_custom_act_api:get_open_custom_act_infos(?CUSTOM_ACT_TYPE_DAILY_CHARGE_CYCLE) of
        [#act_info{key = {_, ActSub}}|_] ->
            NewPlayer = login(Player),
            pp_recharge_act:handle(15955, NewPlayer, [ActSub]),
            pp_recharge_act:handle(15956, NewPlayer, [ActSub]),
            {ok, NewPlayer};
        _ ->
            {ok, Player}
    end;
update(Player) -> {ok, Player}.

%% 更新充值活动
handle_recharge_act(Player, OpenActList) ->
    #player_status{cumulative_charge = Cumulation, id = RoleId, figure = #figure{lv = Lv}} = Player,
    NewCumulation = handle_recharge_act(RoleId, Cumulation, OpenActList, [{lv, Lv}]),
    NewPlayer = Player#player_status{cumulative_charge = NewCumulation},
    lib_recharge_cumulation:update(NewPlayer),
    NewPlayer.
handle_recharge_act(RoleId, Cumulation, [ActInfo|OpenActList], RewardParam) ->
    NowTime = utime:unixtime(),
    case ActInfo of
        #act_info{stime = Stime, etime = ETime, key = {Type, SubType}, wlv = WLv} when ETime >= NowTime ->
            RewardIds = lib_custom_act_util:get_act_reward_grade_list(Type, SubType),
            ZeroTime = utime:unixdate(),
            CycleTime = maps:get({cycle_time, SubType}, Cumulation, Stime),
            F = fun(Id, Acc) ->
                    case lib_custom_act_util:get_act_reward_cfg_info(Type, SubType, Id) of
                        #custom_act_reward_cfg{condition = Condition} ->
                            case lists:keyfind(type, 1, Condition) of
                                {type, 1} -> %% 每日刷新
                                    update_reward_status(RoleId, SubType, Id, ZeroTime, 1, Condition, Acc, [{wlv, WLv}|RewardParam]);
                                {type, 2} -> %% 轮回刷新
                                    update_reward_status(RoleId, SubType, Id, CycleTime, 2, Condition, Acc, [{wlv, WLv}|RewardParam]);
                                _ ->
                                    Acc
                            end;
                        _ ->
                            Acc
                    end
            end,
            NewCumulation = lists:foldl(F, Cumulation, RewardIds),
            handle_recharge_act(RoleId, NewCumulation, OpenActList, RewardParam);
        _ ->
            handle_recharge_act(RoleId, Cumulation, OpenActList, RewardParam)
    end;

handle_recharge_act(_RoleId, Cumulation, [], _) -> Cumulation.

%% 更新奖励领取状态
update_reward_status(RoleId, SubType, Id, Time, Type, Condition, Cumulation, RewardParam) ->
    case maps:find({reward, SubType, Id}, Cumulation) of
        {ok, {Time, _State, _Info}} -> %% 已领取过
            Cumulation;
        Sth -> %% 未领取
            case check_reward_condition(RoleId, Type, Condition, Time) of
                true -> %% 可领取
                    case Sth of
                        {ok, {OldTime, 0, Info}} ->
                            send_forgot_rewards(RoleId, SubType, Id, Info, OldTime); %% 发送未领取的奖励
                        _ ->
                            skip
                    end,
                    save_reward_status(RoleId, SubType, Id, Time, 0, RewardParam),
                    case lists:keyfind(cycle, 1, Condition) of
                        {cycle, _} ->
                            NewCycleTime = utime:unixdate() + ?ONE_DAY_SECONDS, %% 新的轮回时间由当天往后一天
                            lib_counter:set_count_offline(RoleId, ?MOD_RECHARGE_ACT, ?MOD_RECHARGE_ACT_CUMULATION, SubType, NewCycleTime),
                            Cumulation#{{reward, SubType, Id} => {Time, 0, RewardParam}, {cycle_time, SubType} => NewCycleTime};
                        _ ->
                            Cumulation#{{reward, SubType, Id} => {Time, 0, RewardParam}}
                    end;
                _ -> %% 不可领取
                    Cumulation
            end
    end.

%% 返还忘记领取的奖励
send_forgot_rewards(RoleId, [[SubType, Id, Info, OldTime]|ForgotList]) ->
    send_forgot_rewards(RoleId, SubType, Id, Info, OldTime),
    send_forgot_rewards(RoleId, ForgotList);

send_forgot_rewards(_RoleId, []) -> ok.

send_forgot_rewards(_RoleId, SubType, Id, Info, _OldTime) ->
    case lib_custom_act_util:get_act_reward_cfg_info(?CUSTOM_ACT_TYPE_DAILY_CHARGE_CYCLE, SubType, Id) of
        #custom_act_reward_cfg{condition = Condition} = RewardCfg ->
            RwParam = info_2_rwparam(#reward_param{}, Info),
            case lib_custom_act_util:count_act_reward(RwParam, RewardCfg) of
                [_|_] = _RewardList ->
                    case lists:keyfind(gold, 1, Condition) of
                        {gold, _Gold} ->
                            case lists:keyfind(type, 1, Condition) of
                                {type, 1} ->
                                    % TimeText = utext:get_mm_dd_time_text(OldTime),
                                    % Title   = utext:get(290, [Gold]),
                                    % Content = utext:get(291, [TimeText, Gold]),
                                    % lib_mail_api:send_sys_mail([RoleId], ?MOD_RECHARGE_ACT, Title, Content, RewardList);
                                    ok;
                                {type, 2} ->
                                    case lists:keyfind(day, 1, Condition) of
                                        {day, _Day} ->
                                            % Title   = utext:get(292, [Day, Gold]),
                                            % Content = utext:get(293, [Day, Gold]),
                                            % lib_mail_api:send_sys_mail([RoleId], ?MOD_RECHARGE_ACT, Title, Content, RewardList);
                                            ok;
                                        _ ->
                                            ok %% 配置不对，忽略
                                    end;
                                _ ->
                                    ok %% 配置不对，忽略
                            end;
                        _ ->
                            ok %% 配置不对，忽略
                    end;
                _ ->
                    ok %% 配置不对，忽略
            end;
        _ ->
            ok %% 配置不对，忽略
    end.

info_2_rwparam(Param, [{lv, Lv}|T]) ->
    info_2_rwparam(Param#reward_param{player_lv = Lv}, T);

info_2_rwparam(Param, [{wlv, WLv}|T]) ->
    info_2_rwparam(Param#reward_param{wlv = WLv}, T);

info_2_rwparam(Param, [_|T]) ->
    info_2_rwparam(Param, T);

info_2_rwparam(Param, []) -> Param.


check_reward_condition(RoleId, 1, Condition, _Time) ->
    TodayGold = lib_recharge_data:get_today_pay_gold(RoleId),
    {gold, Gold} = lists:keyfind(gold, 1, Condition),
    case lists:keyfind(gold, 1, Condition) of
        {gold, Gold} when TodayGold >= Gold ->
            true;
        _ ->
            false
    end;

check_reward_condition(RoleId, 2, Condition, StartTime) ->
    NowTime = utime:unixtime(),
    if
        StartTime < NowTime ->
            HistoryList = lib_recharge_data:get_my_daily_recharge_summaries(RoleId, StartTime),
            case lists:keyfind(gold, 1, Condition) of
                {gold, Gold} ->
                    case lists:keyfind(day, 1, Condition) of
                        {day, Day} ->
                            X = lists:sum([1 || {_, {G, _}} <- HistoryList, G >= Gold]),
                            if
                                X >= Day ->
                                    true;
                                true ->
                                    false
                            end;
                        _ ->
                            false
                    end;
                _ ->
                    false
            end;
        true ->
            already_get
    end;

check_reward_condition(_RoleId, _, _Condition, _Time) -> false.

receive_reward(Player, SubType, Id) ->
    case lib_custom_act_util:get_custom_act_open_info(?CUSTOM_ACT_TYPE_DAILY_CHARGE_CYCLE, SubType) of
        #act_info{stime = _STime} = ActInfo ->
            case lib_custom_act_util:get_act_reward_cfg_info(?CUSTOM_ACT_TYPE_DAILY_CHARGE_CYCLE, SubType, Id) of
                RewardCfg when is_record(RewardCfg, custom_act_reward_cfg) ->
                    case get_reward_state(Player, ActInfo, RewardCfg) of
                        {?ACT_REWARD_CAN_GET, Time} ->
                            case lib_custom_act_util:count_act_reward(Player, ActInfo, RewardCfg) of
                                [_|_] = RewardList ->
                                    try_do_receive_reward(Player, RewardList, SubType, Id, Time);
                                _ ->
                                    {false, ?ERRCODE(err331_no_act_reward_cfg)}
                            end;
                        {?ACT_REWARD_HAS_GET, _} ->
                            {false, ?ERRCODE(err331_already_get_reward)};
                        _ ->
                            {false, ?ERRCODE(err331_act_can_not_get)}
                    end;
                _ ->
                    {false, ?ERRCODE(err331_no_act_reward_cfg)}
            end;
        _ ->
            {false, ?ERRCODE(err331_act_closed)}
    end.

try_do_receive_reward(Player, RewardList, SubType, Id, Time) ->
    case lib_goods_api:can_give_goods(Player, RewardList) of
        true ->
            #player_status{id = RoleId, cumulative_charge = Cumulation} = Player,
            NewCumulation = Cumulation#{{reward, SubType, Id} => {Time, 1, []}},
            save_reward_status(RoleId, SubType, Id, Time, 1, []),
            Produce = #produce{type = ac_recharge_cumulation, subtype = Id, reward = RewardList, remark = integer_to_list(Id)},
            NewPlayer = lib_goods_api:send_reward(Player, Produce),
            {ok, NewPlayer#player_status{cumulative_charge = NewCumulation}};
        _ ->
            {false, ?ERRCODE(err150_no_cell)}
    end.

get_reward_state(Player, #act_info{key = {_, SubType}, stime = STime}, #custom_act_reward_cfg{grade = Id,  condition = Condition}) ->
    #player_status{cumulative_charge = Cumulation, id = RoleId} = Player,
    case lists:keyfind(type, 1, Condition) of
        {type, Type} ->
            CycleTime = maps:get({cycle_time, SubType}, Cumulation, 0),
            Time =
            if
                Type =:= 1 -> utime:unixdate();
                CycleTime =:= 0 -> STime;
                true -> CycleTime
            end,
            case maps:find({reward, SubType, Id}, Cumulation) of
                {ok, {WhateverTime, 0, _}} ->
                    {?ACT_REWARD_CAN_GET, WhateverTime};
                {ok, {Time, 1, _}}  ->
                    {?ACT_REWARD_HAS_GET, Time};
                {ok, {DiffTime, 1, _}} when Type =:= 2 andalso CycleTime =:= 0 ->
                    {?ACT_REWARD_HAS_GET, DiffTime};
                _ ->
                    case check_reward_condition(RoleId, Type, Condition, Time) of
                        true ->
                            {?ACT_REWARD_CAN_GET, Time};
                        already_get ->
                            {?ACT_REWARD_HAS_GET, Time};
                        _ ->
                            {?ACT_REWARD_CAN_NOT_GET, Time}
                    end
            end;
        _ ->
            {?ACT_REWARD_CAN_NOT_GET, 0}
    end.

save_reward_status(RoleId, SubType, Id, Time, State, Info) ->
    SQL = io_lib:format("REPLACE INTO `recharge_cumulation_reward` (`player_id`, `subtype`, `id`, `time`, `state`, `info`) VALUES (~p, ~p, ~p, ~p, ~p, '~s')", [RoleId, SubType, Id, Time, State, util:term_to_string(Info)]),
    db:execute(SQL).

delete_forgot_list(_RoleId, []) -> ok;
delete_forgot_list(RoleId, DelList) ->
    Conditions = [io_lib:format("(`subtype`=~p AND `id`=~p)", [SubType, Id]) || [SubType, Id|_] <- DelList],
    ConditionsStr = ulists:list_to_string(Conditions, " OR "),
    SQL = io_lib:format("DELETE FROM `recharge_cumulation_reward` WHERE `player_id`=~p AND (~s)", [RoleId, ConditionsStr]),
    db:execute(SQL).

