%% ---------------------------------------------------------------------------
%% @doc    充值系统数据处理
%% @author hek
%% @since  2016-11-14
%% @deprecated
%% ---------------------------------------------------------------------------

-module (lib_recharge_data).
-include ("server.hrl").
-include ("common.hrl").
-include ("def_recharge.hrl").
-include ("rec_recharge.hrl").
-include ("def_cache.hrl").
-include ("def_module.hrl").

-export([
        get_all_recharge/0
        ,get_my_all_recharge/1
        ,finish_recharge/1

        ,get_my_recharge_between/3
        ,get_my_daily_recharge_summaries/2
        ,get_recharge_between/3

        ,get_total/1
        ,get_total_rmb/1
        ,get_today_pay_gold/1
        ,get_player_pay_above/1
        % ,get_gold_detail_between/3

        ,db_insert_recharge_log/6
        ,db_update_player_last_pay_time/2

        ,update_total_rmb/2
        ,update_daily_recharge/4
        ,update_total_gold/2
        ,db_save_recharge_statistic/2

        ,get_daily_recharge_detail/2
        ,get_daily_month_recharge_record/1
    ]).
-export([
        get_recharge_roles/2
        ,get_recharge_role_ids/2
    ]).

%% 取出所有未处理的充值记录
get_all_recharge() ->
    db:get_all(?sql_pay_fetch_all).

%% 取出玩家所有充值待处理记录
get_my_all_recharge(PlayerId) ->
    db:get_all(io_lib:format(?sql_pay_fetch_all_of_user, [PlayerId])).

%% 将充值记录标识为已经完成处理
finish_recharge(Id) ->
    goods_transaction:add_sql(io_lib:format(?sql_pay_update_recharge, [Id])).

%% 获取充值总额-元宝
get_total(PlayerId) ->
    CacheKey = ?CACHE_KEY(?CACHE_TOTAL_RECHARGE, ?PAY_TOTAL_RECHARGE(PlayerId)),
    case mod_cache:get(CacheKey) of
        undefined ->
            Recharge = case db:get_one(io_lib:format(?sql_recharge_get_total, [PlayerId])) of
                Total when is_number(Total) -> round(Total);
                _ -> 0
            end,
            mod_cache:put(CacheKey, Recharge),
            Recharge;
        Money ->
            Money
    end.

%% 获取充值总额-钱
get_total_rmb(PlayerId) ->
    CacheKey = ?CACHE_KEY(?CACHE_TOTAL_RMB, PlayerId),
    case mod_cache:get(CacheKey) of
        undefined ->
            Recharge = case db:get_one(io_lib:format(?sql_get_pay_rmb_sum, [PlayerId])) of
                           M when is_number(M) -> M;
                           _ -> 0
                       end,
            mod_cache:put(CacheKey, Recharge),
            Recharge;
        Money ->
            Money
    end.

%% 更新充值金额-钱
update_total_rmb(_PlayerId, 0) -> ok;
update_total_rmb(PlayerId, Rmb) ->
    CacheKey = ?CACHE_KEY(?CACHE_TOTAL_RMB, PlayerId),
    case mod_cache:get(CacheKey) of
        undefined ->
            skip;
        Money ->
            mod_cache:put(CacheKey, Money + Rmb)
    end.

%% 更新充值游戏币总额
update_total_gold(_RoleId, 0) -> ok;
update_total_gold(RoleId, Gold) ->
    CacheKey = ?CACHE_KEY(?CACHE_TOTAL_RECHARGE, ?PAY_TOTAL_RECHARGE(RoleId)),
    case mod_cache:get(CacheKey) of
        undefined ->
            skip;
        Total ->
            mod_cache:put(CacheKey, Total + Gold)
    end.

%% 获取 StartTime 到现在每天的充值总额，包括今天， 只能在玩家进程获取
%% return [{每天0点时间戳,{元宝总数，人民币总数}}]
get_my_daily_recharge_summaries(RoleId, StartTime) ->
    Cache = get_daily_recharge_detail(RoleId, StartTime),
    [{Time, {Gold, Rmb}} || #daily_recharge{zero_time = Time, total_gold = Gold, total_rmb = Rmb} <- Cache].

%% 获取 StartTime 到现在的充值总额
get_my_recharge_between(RoleId, StartTime, EndTime) when StartTime < EndTime ->
    Cache = get_daily_recharge_detail(RoleId, utime:unixdate(StartTime)),
    HisSum = lists:sum([G || #daily_recharge{detail = Details} <- Cache, [CTime, G|_] <- Details, StartTime =< CTime andalso CTime < EndTime]),
    HisSum;
get_my_recharge_between(_, _, _) -> 0.

%% 获取玩家当天充值量
get_today_pay_gold(RoleId) ->
    case get_daily_recharge_detail(RoleId, utime:unixdate()) of
        [#daily_recharge{total_gold = Gold}|_] ->
            Gold;
        _ ->
            0
    end.
%% ---------------------------------------------------------------------------
%% @doc 获取玩家从某个时间点开始到现在的充值记录。注意：精度只精确到每天
-spec get_daily_recharge_detail(RoleId, StartTime) -> Return when
    RoleId      :: integer(),
    StartTime   :: integer(),
    Return      :: [#daily_recharge{}].
%% ---------------------------------------------------------------------------
get_daily_recharge_detail(RoleId, StartTime) when StartTime >= 0 ->
    AllCache = get_daily_recharge(RoleId),
    [X || #daily_recharge{zero_time = Time} = X <- AllCache, Time >= StartTime];
get_daily_recharge_detail(_, _) -> [].

%% 获得每日充值数据
get_daily_recharge(RoleId) ->
    case get({?MOD_RECHARGE_ACT, daily_recharge_detail}) of
        Cache when is_list(Cache) ->
            Cache;
        _ ->
            Cache = load_all_daily_recharge(RoleId),
            put({?MOD_RECHARGE_ACT, daily_recharge_detail}, Cache),
            Cache
    end.

%% 每日充值的金额只更新缓存就行了
%% 这个时间用的是充值到账的时间
update_daily_recharge(_RoleId, NowTime, Gold, Rmb) when Gold > 0 orelse Rmb > 0 ->
    case get({?MOD_RECHARGE_ACT, daily_recharge_detail}) of
        Cache when is_list(Cache) ->
            ZeroTime = utime:unixdate(NowTime),
            Detail = [NowTime, Gold, Rmb],
            NewCache
                = case lists:keyfind(ZeroTime, #daily_recharge.zero_time, Cache) of
                      #daily_recharge{total_gold = G, total_rmb = R, detail = D} = DailyRec ->
                          NewDailyRec = DailyRec#daily_recharge{total_gold = G + Gold, total_rmb = R + Rmb, detail = [Detail|D]},
                          lists:keystore(ZeroTime, #daily_recharge.zero_time, Cache, NewDailyRec);
                      _ ->
                          [#daily_recharge{zero_time = ZeroTime, total_gold = Gold, total_rmb = Rmb, detail = [Detail]} | Cache]
                  end,
            put({?MOD_RECHARGE_ACT, daily_recharge_detail}, NewCache);
        _ ->
            ok
    end;

update_daily_recharge(_RoleId, _NowTime, _Money, _Rmb) -> ok.


%% 获取一定时间内充值的总数（读数据库）
get_recharge_between(RoleId, STime, ETime) ->
    Sql = io_lib:format(?sql_pay_task_get_gold, [RoleId, STime, ETime]),
    db:get_one(Sql).

%% 获取开服到现在的玩家充值记录{每日充值记录，每月充值记录}
get_daily_month_recharge_record(PS) ->
    SumList = lib_recharge_data:get_my_daily_recharge_summaries(PS#player_status.id, 0),
    NewDailySumList = [{Gold, ZeroTime} || {ZeroTime, {Gold, _Cash}} <- SumList, Gold > 0],
    F = fun({_Gold, ZeroTime}, MonthSum) ->
        {StartTime, EndTime} = utime:get_month_unixtime_range(ZeroTime),
        case lists:keyfind(StartTime, 2, MonthSum) of
            {_, StartTime} -> %% 已有数据，不做计算
                MonthSum;
            _ ->
                MonthGoldList = [TmpGold || {TmpGold, TmpZeroTime}<-NewDailySumList, TmpZeroTime >= StartTime andalso TmpZeroTime =< EndTime],
                MonthAllGold = lists:sum(MonthGoldList),
                [{MonthAllGold, StartTime} | MonthSum]
        end
    end,
    MonthSum = lists:foldl(F, [], NewDailySumList),
    {NewDailySumList, MonthSum}.

%% 获取充值数在一定数额以上的玩家id
get_player_pay_above(TotalRecharge) ->
    Sql = io_lib:format(?sql_pay_gold_player_id, [TotalRecharge]),
    RoleIds = db:get_all(Sql),
    lists:flatten(RoleIds).

%% 加载所有充值记录
load_all_daily_recharge(RoleId) ->
    SqlLoadRecharge = util:fmt_bin(
        <<"SELECT `time`, `gold`, `money` FROM `recharge_log` WHERE `player_id`=~p">>,
        [RoleId]
    ),
    AllRechargeLog = db:get_all(SqlLoadRecharge),
    {StartTime, EndTime} =
    case AllRechargeLog of
        [_|_] ->
            TimeList = [Time || [Time | _] <- AllRechargeLog],
            {lists:min(TimeList), lists:max(TimeList)};
        _ ->
            NowTime = utime:unixtime(),
            {NowTime, NowTime}
    end,
    LoadTimeScope = [{StartTime, EndTime}],
    LoadedList = load_daily_recharge_cache(LoadTimeScope, AllRechargeLog, []),
    TodayZero = utime:unixdate(),
    case lists:keymember(TodayZero, #daily_recharge.zero_time, LoadedList) of
        true  ->
            LoadedList;
        false ->
            TodayDailyRecharge = #daily_recharge{
                zero_time = TodayZero
                ,total_gold = 0
                ,total_rmb = 0
                ,detail = []
            },
            [TodayDailyRecharge | LoadedList]
    end.

%% LoadTimeScope中，不同的时间段所属日期不能有重叠日期。
%% 严格意义上来说，EndTime也应该是某天最后一秒（除非是还未到的未来时间）
%% 通常来说，应该只有一个时间段范围。
%% 这些都是由于上层原设计逻辑所致
load_daily_recharge_cache([{StartTime, EndTime} | LoadTimeScope], ChargeOrders, Acc) ->
    StartZero = utime:unixdate(StartTime),
    [RestChargeOrders, NewAcc] = part_charge_data_daily(StartZero, EndTime, ChargeOrders, Acc),
    load_daily_recharge_cache(LoadTimeScope, RestChargeOrders, NewAcc);
load_daily_recharge_cache([], _ChargeOrders, Acc) ->
    Acc.

%% 单个时间范围内，每天的充值数据分离统计，如果为0则过滤数据
part_charge_data_daily(StartZero, EndTime, ChargeOrders, Acc) when StartZero < EndTime ->
    %% 防止夏令时问题，不能直接加?ONE_DAY_SECONDS
    NextZero = utime:unixtime({tomorrow, StartZero}),
    {DailyOrders, OtherOrders} = lists:partition(
        fun ([OrderTime, _Gold, _Money]) ->
                OrderTime >= StartZero andalso OrderTime < NextZero;
            (_) -> false
        end, ChargeOrders),
    {DailyGoldSum, DailyMoneySum} = lists:foldl(
        fun ([_OrderTime, Gold, Money], {GoldSum, MoneySum}) ->
                {GoldSum + Gold, Money + MoneySum};
            (_, AccX) -> AccX
        end, {0, 0}, DailyOrders),
    case DailyGoldSum > 0 orelse DailyMoneySum > 0 of
        true  ->
            DailyRecharge = #daily_recharge{
                zero_time = StartZero
                ,total_gold = DailyGoldSum
                ,total_rmb = DailyMoneySum
                ,detail = DailyOrders
            },
            part_charge_data_daily(NextZero, EndTime, OtherOrders, [DailyRecharge | Acc]);
        false ->
            part_charge_data_daily(NextZero, EndTime, OtherOrders, Acc)
    end;
part_charge_data_daily(_, _, RestChargeOrders, Acc) ->
    [RestChargeOrders, Acc].

%% 插入充值记录
db_insert_recharge_log(PS, Type, ProductId, Money, Gold, Time) ->
    #player_status{accid = AccId, accname = AccName, id = PlayerId} = PS,
    Sql = io_lib:format(?sql_insert_recharge_log, [AccId, AccName, PlayerId, Type, ProductId, Money, Gold, Time]),
    goods_transaction:add_sql(Sql).

%% 更新玩家最后充值时间
db_update_player_last_pay_time(PlayerId, LastPayTime) ->
    Sql = io_lib:format(?sql_update_last_pay_time, [LastPayTime, PlayerId]),
    goods_transaction:add_sql(Sql).

%% 保存充值统计信息
db_save_recharge_statistic(RoleId, RechargeStatistic) ->
    #role_recharge_statistic{
        last_pay_time = LastPayTime
        , total_money = TotalMoney
        , total_gold = TotalGold
        %% 根据上面参数计算的评级
        , recency = Recency
        , frequency = Frequency
        , monetary = Monetary
        , top = Top
    } = RechargeStatistic,
    Sql = io_lib:format(?sql_save_recharge_statistic, [RoleId, LastPayTime, TotalMoney, TotalGold, Recency, Frequency, Monetary, Top]),
    goods_transaction:add_sql(Sql).

%% 从数据库中，获取指定时间段有充值的角色列表，包括角色id及其充值gold值
%% 注意时间范围区间，为左闭右开，EndTime通常可能需要加1秒，视需要自定
get_recharge_roles(StartTime, EndTime) ->
    Sql = io_lib:format(?SQL_SELECT_PAY_ROLES_GOLD, [StartTime, EndTime]),
    db:get_all(Sql).

get_recharge_role_ids(StartTime, EndTime) ->
    Sql = io_lib:format(?SQL_SELECT_PAY_ROLE_IDS, [StartTime, EndTime]),
    db:get_all(Sql).
