%%-----------------------------------------------------------------------------
%% @Module  :       lib_investment.erl
%% @Author  :       J
%% @Email   :       j-som@foxmail.com
%% @Created :       2017-12-18
%% @Description:    投资活动
%%-----------------------------------------------------------------------------

-module (lib_investment).
-include ("server.hrl").
-include ("investment.hrl").
-include ("errcode.hrl").
-include ("figure.hrl").
-include ("common.hrl").
-include ("goods.hrl").
-include ("def_module.hrl").
-include ("red_envelopes.hrl").

-export ([
    login/1
    ,get_investment_info/1
    ,investment/2
    ,send_reward/3
    ,gm_reset/2
    ]).

%% 上线初始化
login(RoleId) ->
    SQL = io_lib:format(?sql_select_investment_data, [RoleId]),
    InvestmentStatus = init_status(db:get_all(SQL), #{}),
    InvestmentStatus.

init_status([[Type, Lv, IsBuy, RewardInfoStr, BuyTime]|T], InvestmentMap) ->
    RewardInfo = util:bitstring_to_term(RewardInfoStr),
    init_status(T, InvestmentMap#{Type => #investment{type = Type, round = Lv, is_buy = IsBuy,buy_time = BuyTime, reward_info = RewardInfo}});

init_status([], InvestmentMap) -> InvestmentMap.

%% 发送投资信息
get_investment_info(PS) ->
    #player_status{investment = InvestmentStatus} = PS,
    Info = [
        begin
            #investment{
                round = Round,
                is_buy = IsBuy,
                buy_time = BuyTime,
                reward_info = RewardInfo
            } = maps:get(Type, InvestmentStatus, default_investment(Type)),
            {Type, Round, IsBuy, BuyTime, RewardInfo}
        end
        || Type <- data_investment:get_all_investment_type()
    ],
    Info.

check_investment(Player, Type) ->
    #player_status{investment = InvestmentStatus} = Player,
    Item = maps:get(Type, InvestmentStatus, default_investment(Type)),
    Cfg = data_investment:get_type(Type, Item#investment.round),
    if
        Item#investment.is_buy =:= 1 -> {false, ?ERRCODE(err420_already_buy)};
        not is_record(Cfg, base_investment_type) -> {false, ?MISSING_CONFIG};
        true ->
            #base_investment_type{condition = Condition, price = Price, price_type = PriceType} = Cfg,
            case check_condition(Player, Item, Condition) of
                true  ->
                    NewItem = #investment{
                        type = Type,
                        round = Item#investment.round,
                        is_buy = 1,
                        buy_time = utime:unixdate(),
                        reward_info = []
                    },
                    {true, [{PriceType, 0, Price}], NewItem};
                {false, Error} ->
                    {false, Error}
            end
    end.

%% 购买投资
investment(Player, Type) ->
    #player_status{
        investment = InvestmentStatus,
        id = RoleId,
        figure = #figure{name = Name, lv = Lv, vip = Vip}
    } = Player,
    case check_investment(Player, Type) of
        {true, Cost, NewItem} ->
            case lib_goods_api:cost_object_list_with_check(Player, Cost, investment_buy, ulists:concat([Type, " | ", NewItem#investment.round])) of
                {true, Player1, _} ->
                    save_investment(RoleId, NewItem),
                    NewInvestmentStatus = maps:put(Type, NewItem, InvestmentStatus),
                    Player2 = Player1#player_status{investment = NewInvestmentStatus},
                    lib_chat:send_TV({all}, ?MOD_INVESTMENT, Type, [Name, RoleId]),
                    lib_red_envelopes:trigger_red_envelopes(Player, ?RED_ENVELOPES_TYPE_INVESTMENT, [{invest, Type}]),
                    PlayerEnd = Player2,
                    lib_log_api:log_investment(
                        [RoleId, Name, Type, NewItem#investment.round, 0, "[]", "[]", Lv, Vip, utime:unixtime()]
                    ),
                    custom_act_mobilize:update_mobilize_task(RoleId,investment,1),
                    {true, PlayerEnd};
                {false, Error, _} ->
                    {false, Error}
            end;
        {false, Error} ->
            {false, Error}
    end.

check_send_reward(Player, Type, RewardId) ->
    #player_status{investment = InvestmentStatus} = Player,
    Item    = maps:get(Type, InvestmentStatus, default_investment(Type)),
    IsAward = lists:member(RewardId, Item#investment.reward_info),
    Cfg     = data_investment:get_reward(Type, Item#investment.round, RewardId),
    if
        Item#investment.is_buy =:= 0 -> {false, ?ERRCODE(err420_no_investment)};
        IsAward -> {false, ?ERRCODE(err420_reward_is_got)};
        not is_record(Cfg, base_investment_reward) -> {false, ?MISSING_CONFIG};
        true ->
            case check_condition(Player, Item, Cfg#base_investment_reward.condition) of
                {false, Error} ->
                    {false, Error};
                {false, Error, Extra} ->
                    {false, {Error, Extra}};
                true  ->
                    {true, Item, Cfg}
            end
    end.

%% 领取投资奖励
send_reward(PS, Type, RewardId) ->
    #player_status{
        id = RoleId,
        investment = InvestmentStatus,
        figure = #figure{name = Name, lv = Lv, vip = Vip}
    } = PS,
    case check_send_reward(PS, Type, RewardId) of
        {false, Error} ->
            {false, Error};
        {true, Item, #base_investment_reward{rewards = Award, condition = Condition}} ->
            RewardInfo = Item#investment.reward_info,
            Item1 = Item#investment{reward_info = [RewardId|RewardInfo]},
            Item2 = after_award_check_round(Item1),
            NewInvestmentStatus = InvestmentStatus#{Type => Item2},
            save_investment(RoleId, Item2),
            Produce = #produce{type = investment_reward, reward = Award, remark = ulists:concat(["Type:", Type, ",round:", Item#investment.round, ",id:", RewardId])},
            RewardPS = lib_goods_api:send_reward(PS, Produce),
            LastPS = RewardPS#player_status{investment = NewInvestmentStatus},
            lib_log_api:log_investment(
                [RoleId, Name, Type, Item#investment.round, RewardId, util:term_to_bitstring(Award), util:term_to_bitstring(Condition), Lv, Vip, utime:unixtime()]
            ),
            {true, LastPS, Item1 /= Item2}
    end.

after_award_check_round(Item) ->
    #investment{
        type        = Type,            %% 投资类型
        round       = Round,           %% 投资档位
        reward_info = RewardInfo
    } = Item,
    AllIds = data_investment:get_all_reward_id(Type, Round),
    case AllIds -- RewardInfo of
        [] ->
            %% 所有奖励都领完了
            case data_investment:get_type(Type, Round) of
                #base_investment_type{clear_type = 1} ->
                    %% 领完重置当前轮次
                    #investment{
                        type = Type,
                        round = Round
                    };
                #base_investment_type{clear_type = 0} ->
                    %% 领完不重置，自动跳到下一轮
                    #investment{
                        type = Type,
                        round = Round+1
                    }
            end;
        _  ->
            Item
    end.

gm_reset(Player, Type) ->
    #player_status{investment = InvestmentStatus} = Player,
    NewPlayer = Player#player_status{investment = maps:remove(Type, InvestmentStatus)},
    pp_investment:handle(42001, NewPlayer, []),
    NewPlayer.
%% --------------- sql ---------------------
%% 保存投资信息
save_investment(RoleId, Item) ->
    #investment{
        type = Type,
        round = Round,
        is_buy = IsBuy,
        buy_time = BuyTime,
        reward_info = RewardInfo
    } = Item,
    SQL = io_lib:format(?sql_save_investment_data, [RoleId, Type, Round, IsBuy, BuyTime, util:term_to_bitstring(RewardInfo)]),
    db:execute(SQL).

%% 条件检查
check_condition(Player, Item, [{lv, Lv}|T]) ->
    #player_status{figure = #figure{lv = RoleLv}} = Player,
    if
        RoleLv >= Lv -> check_condition(Player, Item, T);
        true -> {false, {?ERRCODE(player_lv_less), [Lv]}}
    end;
check_condition(_Player, #investment{buy_time = 0}, [{day, _NeedDay}|_]) ->
    {false, ?ERRCODE(err420_no_investment)};
check_condition(Player, Item, [{day, NeedDay}|T]) ->
    DiffDays = utime:day_span(Item#investment.buy_time),
    if
        DiffDays >= NeedDay -> check_condition(Player, Item, T);
        true -> {false, {?ERRCODE(err420_need_more_day), [NeedDay]}}
    end;
check_condition(_Player, _Item, [_|_]) ->
    {false, 0};
check_condition(_, _, []) -> true.

default_investment(Type) ->
    #investment{type = Type, round = ?INVESTMENT_DEFAULT_ROUND}.
