%%%-------------------------------------------------------------------
%%% @author liushl
%%% @doc
%%% 离线托管数据, 托管值和托管设置保存在ETS表中，查询的时候会进行判断：如果跨周会进行重置结算
%%% 另外，每天7点会清理30天之前的托管日志
%%% @end
%%%-------------------------------------------------------------------
-module(offline_hosting_data).
-author("liushl").

-include("offline_hosting.hrl").
-include("server.hrl").
-include("def_module.hrl").
-include("def_goods.hrl").
-include("figure.hrl").
%% API
-export([]).
-compile(export_all).

%%%-------------------------------------------------------------------
%%% @doc 托管设置
%%%-------------------------------------------------------------------
%% 加载所有玩家的离线托管设置
load_all_host_setting() ->
    AllData = db:get_all(?HOST_LOAD_ALL),
    Info = [
        #ets_offline_hosting{
            role_id = RoleId,
            close_list  = util:bitstring_to_term(Setting),
            value       = Value,
            u_time      = UTime
        }
        ||[RoleId, Setting, Value, UTime] <- AllData
    ],
    ets:insert(?ETS_OFFLINE_HOSTING, Info).

host_load_setting_data(RoleId) ->
    SQL = io_lib:format(?HOST_LOAD_DATA, [RoleId]),
    case db:get_row(SQL) of
        [Setting, Value, UTime] ->
            FixSetting = case Setting of
                undefined ->
                    [];
                _ ->
                    util:bitstring_to_term(Setting)
            end,
            #ets_offline_hosting{
                role_id     = RoleId,             %% 玩家id
                close_list    = FixSetting,
                value       = Value,
                u_time      = UTime
            };
        _ ->
            #ets_offline_hosting{
                role_id     = RoleId,             %% 玩家id
                close_list = [],
                value = data_offline_hosting:get_offline_hosting_kv(open_ai),
                u_time = utime:unixtime()
            }
    end.

%% 查询托管设置
%% 查询的时候会判断是否重置托管值
host_setting_lookup(RoleId) ->
    Setting =
        case ets:lookup(?ETS_OFFLINE_HOSTING, RoleId) of
            [#ets_offline_hosting{} = Info] ->
                Info;
            _ ->
                Info = host_load_setting_data(RoleId),
                host_save_setting_ets(Info),
                Info
        end,
    check_week_reset(Setting).

%% 保存托管设置
host_save_setting(#ets_offline_hosting{} = Info) ->
    host_save_setting_ets(Info),
    host_save_setting_db(Info);
host_save_setting(_) -> ok.

host_save_setting_ets(#ets_offline_hosting{} = Info) ->
    ets:insert(?ETS_OFFLINE_HOSTING, Info);
host_save_setting_ets(_) -> ok.

%% 判断是否重置托管值
check_week_reset(OfflineHosting) ->
    #ets_offline_hosting{
        u_time = Utime,
        value = Value
    } = OfflineHosting,
    Now = utime:unixtime(),
    LogicWeekStart = utime:logic_week_start(Now),
    case Utime >= LogicWeekStart of
        true  ->
            %% 同一周
            OfflineHosting;
        false when Value =:= 0 ->
            OfflineHosting;
        false ->
            week_reset(OfflineHosting, Now)
    end.

week_reset(OfflineHosting, Now) ->
    #ets_offline_hosting{
        role_id = RoleId,
        value = Value
    } = OfflineHosting,
    Value2Money = data_offline_hosting:get_offline_hosting_kv(ai_to_money),
    RewardValueCfg = data_offline_hosting:get_offline_hosting_kv(reward_ai),
    NewOfflineHosting =
        case Value >= RewardValueCfg of
            true  ->
                OfflineHosting#ets_offline_hosting{
                    u_time = Now,
                    value = data_offline_hosting:get_offline_hosting_kv(week_ai)
                };
            false ->
                OfflineHosting#ets_offline_hosting{
                    u_time = Now,
                    value = 0
                }
        end,
    host_save_setting(NewOfflineHosting),
    #figure{lv = RoleLv, name = Name} = lib_role:get_role_figure(RoleId),
    lib_log_api:log_offline_hosting_change(
        [RoleId, Name, OfflineHosting#ets_offline_hosting.value, NewOfflineHosting#ets_offline_hosting.value, Now]
    ),
    IsOpen = lib_module:is_open(RoleLv, ?MOD_OFFLINE_HOSTING),
    Money = round(Value / Value2Money),
    case IsOpen andalso Money > 0 of
        true  ->
            Reward = [{?TYPE_BGOLD, 0, Money}],
            Title = utext:get(1130001),
            Content = utext:get(1130002, [Value, Money]),
            lib_mail_api:send_sys_mail([RoleId], Title, Content, Reward);
        false ->
            ok
    end,
    NewOfflineHosting.

%% 清除托管设置
setting_delete(RoleId) ->
    ets:delete(?ETS_OFFLINE_HOSTING, RoleId).

%% 清理设置数据
host_clean_ets() ->
    AllHostId = ets:match(?ETS_OFFLINE_HOSTING, #ets_offline_hosting{role_id = '$1', _ = '_'}),
    [
        case ets:lookup_element(?ETS_OFFLINE_HOSTING, Key, #ets_offline_hosting.value) of
        0 ->
            ets:delete(?ETS_OFFLINE_HOSTING, Key);
        _ ->
            ok
    end || [Key] <- AllHostId
    ].
%%%-------------------------------------------------------------------
%%% @doc 当前正在参与托管的玩家
%%%-------------------------------------------------------------------
hosting_role_lookup(RoleId) ->
    ets:lookup(?ETS_HOSTING_ROLE, RoleId).

hosting_role_save(#ets_hosting_role{} = Info) ->
    ets:insert(?ETS_HOSTING_ROLE, Info);
hosting_role_save(_) -> ok.

hosting_role_is_hosting(RoleId) ->
    case hosting_role_lookup(RoleId) of
        [] -> false;
        _ -> true
    end.

%% 清除托管
hosting_role_delete(RoleId) ->
    ets:delete(?ETS_HOSTING_ROLE, RoleId).

%%%-------------------------------------------------------------------
%%% @doc 托管记录
%%%-------------------------------------------------------------------
hosting_log(RoleId, Award) ->
    case hosting_role_lookup(RoleId) of
        [#ets_hosting_role{award = TotalAward} = RoleInfo] ->
            NewTotal = lib_goods_util:merge_same_goods(Award ++ TotalAward),
            NewRoleInfo = RoleInfo#ets_hosting_role{award = NewTotal},
            hosting_role_save(NewRoleInfo);
        _ ->
            ok
    end.

hosting_log_save_db(Figure) ->
    #figure{id = RoleId, name = Name} = Figure,
    case offline_hosting_data:hosting_role_lookup(RoleId) of
        [#ets_hosting_role{cost_value = CostValue, mod = ModId, sub_id = SubId, award = Award, time = Begin}] ->
            case CostValue == undefined of
                true  ->
                    %% 还未扣除托管值，这种情形一般是玩家在扣除前及时上线，那就不算托管
                    [];
                false ->
                    H = #offline_hosting_log{
                        key = {ModId, SubId}
                        , cost_value = CostValue
                        , award = Award
                        , time = Begin
                    },
                    NewLog = host_behavior_save_log(RoleId, Name, H),
                    [NewLog]
            end;
        _ ->
            []
    end.
%%%-------------------------------------------------------------------
%%% @doc 托管值
%%%-------------------------------------------------------------------
%% 当天获得的托管值
host_daily_value_lookup(RoleId) ->
    lib_daily:get_count(RoleId, ?MOD_OFFLINE_HOSTING, 1).

host_daily_value_save(RoleId, Value) ->
    lib_daily:set_count(RoleId, ?MOD_OFFLINE_HOSTING, 1, Value).

%% 当天获得的活跃度，如果当次获得的活跃度无法全部转化为托管值或者不够转化为托管值
%% 那么会暂时存储到这里，直到下次获得的活跃度累计能够转为为止
host_daily_live_get(RoleId) ->
    lib_daily:get_count(RoleId, ?MOD_OFFLINE_HOSTING, 2).

host_daily_live_save(RoleId, Value) ->
    lib_daily:set_count(RoleId, ?MOD_OFFLINE_HOSTING, 2, Value).

%% 扣除托管值
host_value_cost(RoleId, Mod, SubMod) ->
    Cost = data_offline_hosting:get_offline_hosting_value(Mod, SubMod),
    #ets_offline_hosting{value = Value} = HostSetting = host_setting_lookup(RoleId),
    NewValue = max(0, Value - Cost),
    host_save_setting(
        HostSetting#ets_offline_hosting{value = NewValue, u_time = utime:unixtime()}
    ),
    Cost.
%%%-------------------------------------------------------------------
%%% @doc DB
%%%-------------------------------------------------------------------
%% 保存一条离线托管记录: 一般结束托管的时候保存
host_behavior_save_log(RoleId, Name, Log) ->
    Now = utime:unixtime(),
    #offline_hosting_log{
        key = {ModId, SubId}
        , cost_value = CostValue
        , award = Award
        , time = Begin
    } = Log,
    Duration = Now - Begin,
    SQL = io_lib:format(?HOST_SAVE_LOG, [RoleId, ModId, SubId, CostValue, util:term_to_bitstring(Award), Duration, Begin]),
    db:execute(SQL),
    lib_log_api:log_offline_hosting([RoleId, Name, ModId, SubId, CostValue, util:term_to_bitstring(Award), Duration, Now]),
    Log#offline_hosting_log{duration = Duration}.

%% 保存设置数据
host_save_setting_db(OfflineHosting) ->
    #ets_offline_hosting{
        role_id = RoleId,
        value = Value,
        close_list = CloseList,
        u_time = UTime
    } = OfflineHosting,
    db:execute(io_lib:format(?HOST_SAVE_DATA, [RoleId, util:term_to_bitstring(CloseList), Value, UTime])).

%% 删除一个月前的托管日志
delete_long_time_ago_log() ->
    Time = utime:unixtime() - 30*86400,
    db:execute(?HOST_CLEAN_LOG, [Time]).

%% 删除一个月前的托管设置：影响，对于回归玩家，可以直接拿到初始的托管值
delete_long_time_ago_role() ->
    Time = utime:unixtime() - 30*86400,
    db:execute(?HOST_CLEAN_HOSTING_SETTING, [Time]).
