%%-----------------------------------------------------------------------------
%% @Module  :       lib_flower
%% @Author  :       Czc
%% @Created :       2017-09-05
%% @Description:    鲜花系统
%%-----------------------------------------------------------------------------
-module(lib_flower).
-include("server.hrl").
-include("goods.hrl").
-include("figure.hrl").
-include("errcode.hrl").
-include("predefine.hrl").
-include("common.hrl").
-include("flower.hrl").
-include("role.hrl").
-include("relationship.hrl").
-include("language.hrl").
-include("def_module.hrl").
-include("def_goods.hrl").
-include("def_id_create.hrl").
-include("chat.hrl").
-include("custom_act.hrl").
-include("common_rank.hrl").
-include("rec_event.hrl").
-include("def_event.hrl").
-include("mate.hrl").

-export([
    login/2
    , send_gift/5
    , get_flower_gift_record/1
    , receive_flower_gift/7
    , get_fame_lv/1
    , check_new_flower_record/2     %% 玩家上线检查是否有新的礼物
    , be_throwed_eggs/5
    , get_charm/2
    , update_week_charm/4
    , db_get_role_week_charm/1
    , check/2
    , thank_flower_sender/2
]).

-export([
    daily_timer/1
    , clear/0
    , handle_event/2
    ,role_receive_sp_gift/4
    ]).

make_record(flower_gift_record, [Id, RoleId, OtherId, GoodsId, Num, IsAnonymous, Time, Code, Thank]) ->
    #flower_gift_record{
        id = Id, role_id = RoleId, other_id = OtherId, num = Num, thank = Thank,
        goods_id = GoodsId, anonymous = IsAnonymous, time = Time, code = Code
    };

make_record(sp_gift, [StartTime, Sender, Day, GoodsId, ReceiveTimeBin]) ->
    #sp_gift{
        key = {StartTime, Sender}, start_time = StartTime, day = Day, goods_id = GoodsId,
        sender = Sender, receive_times = util:bitstring_to_term(ReceiveTimeBin)
    }.

%% 登录
login(RoleId, Now) ->
    %% 获取送礼记录
    get_flower_record_on_dict(RoleId),
    Flower =
    case db:get_row(io_lib:format(?sql_sel_role_flower_data, [RoleId])) of
        [] ->
            db:execute(io_lib:format(?sql_insert_flower, [RoleId, 0, 0, 0, 0, 0])),
            #flower{};
        [Charm, Fame, FlowerNum, WeekCharm, UpdateTime | _] ->
            {NewWeekCharm, NewUpdateTime} = update_week_charm(WeekCharm, Now, UpdateTime, 0),
            FameAttr = get_fame_attr(Fame),
            #flower{
                charm = Charm, fame = Fame, attr = FameAttr,
                flower_num = FlowerNum, week_charm = NewWeekCharm,
                update_time = NewUpdateTime}
    end,
    case db:get_all(?sql_get_sp_gift, [RoleId]) of
        SpGiftList = [_|_] ->
            SpGiftList1 = [make_record(sp_gift, [StartTime, Sender, Day, GoodsId, ReceiveTimeBin]) || [StartTime, Sender, Day, GoodsId, ReceiveTimeBin] <- SpGiftList],
            Flower#flower{sp_gift = SpGiftList1};
        _ ->
            Flower
    end.

handle_event(Player, #event_callback{type_id = ?EVENT_LOGIN_CAST}) ->
    #player_status{id = RoleId, flower = RoleFlower} = Player,
    #flower{sp_gift = SpGiftList} = RoleFlower,
    Now = utime:unixtime(),
    NewSpGiftList = lists:foldl(fun(SpGift, TempSpGiftList) ->
        case check_sp_reward(SpGift, Now) of
            {TimeL = [_|_], DbType, NewSpGift} ->
                #sp_gift{key = Key, start_time = StartTime, day = Day, goods_id = GoodsId, sender = Sender, receive_times = ReceiveTimeL} = NewSpGift,
                send_sp_gift(RoleId, TimeL, SpGift),
                if
                    DbType == update ->
                        db:execute(?sql_replace_sp_gift, [RoleId, StartTime, Sender, Day, GoodsId, util:term_to_bitstring(ReceiveTimeL)]),
                        NewTempSpGiftList = lists:keystore(Key, #sp_gift.key, TempSpGiftList, NewSpGift);
                    DbType == delete ->
                        db:execute(?sql_del_sp_gift, [RoleId, StartTime, Sender]),
                        NewTempSpGiftList = lists:keydelete(Key, #sp_gift.key, TempSpGiftList)
                end;
            _ ->
                NewTempSpGiftList = TempSpGiftList
        end,
        NewTempSpGiftList
    end, SpGiftList, SpGiftList),
    NewPlayer = Player#player_status{flower = RoleFlower#flower{sp_gift = NewSpGiftList}},
    {ok, NewPlayer};

handle_event(Player, #event_callback{type_id = ?EVENT_ZERO_CLOCK}) ->
    #player_status{id = RoleId, flower = RoleFlower} = Player,
    #flower{sp_gift = SpGiftList} = RoleFlower,
    Now = utime:unixtime(),
    NewSpGiftList = lists:foldl(fun(SpGift, TempSpGiftList) ->
        case check_sp_reward(SpGift, Now) of
            {TimeL = [_|_], DbType, NewSpGift} ->
                #sp_gift{key = Key, start_time = StartTime, day = Day, goods_id = GoodsId, sender = Sender, receive_times = ReceiveTimeL} = NewSpGift,
                send_sp_gift(RoleId, TimeL, SpGift),
                if
                    DbType == update ->
                        % ?ERR("~p", [ReceiveTimeL]),
                        db:execute(?sql_replace_sp_gift, [RoleId, StartTime, Sender, Day, GoodsId, util:term_to_bitstring(ReceiveTimeL)]),
                        NewTempSpGiftList = lists:keystore(Key, #sp_gift.key, TempSpGiftList, NewSpGift);
                    DbType == delete ->
                        db:execute(?sql_del_sp_gift, [RoleId, StartTime, Sender]),
                        NewTempSpGiftList = lists:keydelete(Key, #sp_gift.key, TempSpGiftList)
                end;
            _A -> %?ERR("~p", [_A]),
                NewTempSpGiftList = TempSpGiftList
        end,
        NewTempSpGiftList
    end, SpGiftList, SpGiftList),
    NewPlayer = Player#player_status{flower = RoleFlower#flower{sp_gift = NewSpGiftList}},
    pp_flower:handle(22308, NewPlayer, []),
    {ok, NewPlayer}.

check_sp_reward(SpGift, Now) ->
    #sp_gift{start_time = StartTime, day = Day, receive_times = ReceiveTimeL} = SpGift,
    AllTimeL= calc_reward_time_range(StartTime, 1, Day, Now, [StartTime]),
    TimeL = calc_need_sp_reward_day(AllTimeL, ReceiveTimeL),
    % ?ERR("all ~p can reward ~p", [AllTimeL, TimeL]),
    NewReceiveTimeL = TimeL ++ ReceiveTimeL,
    NewReceiveLen = length(NewReceiveTimeL),
    DbType =
    if NewReceiveLen >= Day -> delete;
        true -> update
    end,
    {TimeL, DbType, SpGift#sp_gift{receive_times = NewReceiveTimeL}}.

calc_reward_time_range(_Time, Day, Day, _Now, Acc) ->
    Acc;
calc_reward_time_range(Time, _OneDay, _Day, Now, Acc) when Time > Now ->
    Acc;
calc_reward_time_range(Time, OneDay, Day, Now, Acc) ->
    Tomorrow = utime:unixtime({tomorrow, Time}),
    if Tomorrow > Now ->
            Acc;
        true ->
            calc_reward_time_range(Tomorrow, OneDay+1, Day, Now, [Tomorrow|Acc])
    end.

calc_need_sp_reward_day(AllTimeL, ReceiveTimeL) ->
    lists:foldl(fun(Time, Acc) ->
        case lists:any(fun(ReceiveTime) ->
            utime:day_span(Time, ReceiveTime) == 1
        end, ReceiveTimeL) of
            true -> Acc;
            _    -> [Time|Acc]
        end
    end, [], AllTimeL).

send_sp_gift(RoleId, TimeL, OldSpGift) ->
    #sp_gift{day = Day, sender = Sender, goods_id = GoodsId, receive_times = ReceiveTimeL} = OldSpGift,
    GiftType =
    if RoleId == Sender -> sender;
        true -> receiver
    end,
    SortedTimeL = lists:sort(TimeL),
    ReceiveLen = length(ReceiveTimeL),
    send_sp_gift_logic(SortedTimeL, ReceiveLen, Day, Sender, GiftType, GoodsId, RoleId).

send_sp_gift_logic([], _, _, _, _, _, _) -> ok;
send_sp_gift_logic([_Time|Rest], ReceiveLen, Day, Sender, GiftType, GoodsId, RoleId) ->
    case data_flower:get_sp_gift(GoodsId) of
        #base_flower_sp_gift{my_back_reward = Rewards, friend_back_reward = Rewards1} ->
            NewReceiveLen = ReceiveLen + 1,
            if GiftType == sender ->
                    SpGiftReward = Rewards,
                    if NewReceiveLen >= Day ->
                            % ?ERR("~p", [NewReceiveLen]),
                            {Title, Content} = get_sp_gift_mail_format([NewReceiveLen], GiftType);
                        true ->
                            % ?ERR("~p ~p", [NewReceiveLen, Day - NewReceiveLen]),
                            {Title, Content} = get_sp_gift_mail_format([NewReceiveLen, Day - NewReceiveLen], GiftType)
                    end;
                true ->
                    RoleName = lib_role:get_role_name(Sender),
                    SpGiftReward = Rewards1,
                    if NewReceiveLen >= Day ->
                            {Title, Content} = get_sp_gift_mail_format([RoleName, NewReceiveLen], GiftType);
                        true ->
                            {Title, Content} = get_sp_gift_mail_format([RoleName, NewReceiveLen, Day - NewReceiveLen], GiftType)
                    end
            end,
            lib_mail_api:send_sys_mail([RoleId], Title, Content, SpGiftReward),
            send_sp_gift_logic(Rest, NewReceiveLen, Day, Sender, GiftType, GoodsId, RoleId);
        _ ->
            send_sp_gift_logic(Rest, ReceiveLen, Day, Sender, GiftType, GoodsId, RoleId)
    end.

db_get_role_week_charm(RoleId) ->
    case db:get_one(?sql_select_week_charm, [RoleId]) of
        WeekCharm when is_integer(WeekCharm) ->
            WeekCharm;
        _ ->
            0
    end.

need_update_week_charm(Now, UpdateTime) ->
    case utime:is_same_week(Now, UpdateTime) of
        true ->
            false;
        _ ->
            true
    end.

update_week_charm(WeekCharm, Now, UpdateTime, CharmPlus) ->
    NeedUpdate = need_update_week_charm(Now, UpdateTime),
    if  NeedUpdate ->
            {CharmPlus, Now};
        true -> %% false
            if CharmPlus == 0 -> %% 兼容登录检查
                    {WeekCharm, UpdateTime};
                true ->
                    {round(WeekCharm+CharmPlus), Now}
            end
    end.

%% 获取礼物记录(玩家进程)
get_flower_record_on_dict(RoleId) ->
    case get(role_flower_record) of
        undefined ->
            FlowerRecordList =
             case get_flower_record_on_db(RoleId) of
                   Data = [_|_] ->
                       [make_record(flower_gift_record, OneData) || OneData <- Data];
                   _ -> []
             end,
            save_flower_record_on_dict(FlowerRecordList),
            FlowerRecordList;
        Val -> Val
    end.

get_flower_record_on_db(RoleId) ->
    db:get_all(io_lib:format(?sql_get_gift_record, [RoleId, ?FLOWER_RECORD_NUM_LIMIT*2])).

%% 保存礼物记录(进程)
save_flower_record_on_dict(FlowerRecord) ->
    put(role_flower_record, FlowerRecord).

%% 获取礼物记录
get_flower_gift_record(RoleId) ->
    RecordList = get_flower_record_on_dict(RoleId),
    ExpireTime = utime:unixtime() - ?RECORD_VAILD_TIME,
    pack_gift_record(RecordList, {0, 0}, ExpireTime, []).
pack_gift_record([], {_SendLen, _ReceiveLen}, _ExpireTime, AccL) -> AccL;
pack_gift_record(_, {SendLen, ReceiveLen}, _ExpireTime, AccL)
 when SendLen >= ?FLOWER_RECORD_NUM_LIMIT andalso ReceiveLen >= ?FLOWER_RECORD_NUM_LIMIT ->
    AccL;
pack_gift_record([T|L], {SendLen, ReceiveLen}, ExpireTime, AccL) ->
    case T of
        #flower_gift_record{
            id = Id,
            other_id = OtherId,
            goods_id = GoodsId,
            num = Num,
            anonymous = IsAnonymous,
            time = Time,
            code = Code,
            thank = Thank
        } when Time > ExpireTime -> %% 过期的礼物记录不发给客户端
            if Code == 2 ->
                    NewSendLen = SendLen,
                    NewReceiveLen = ReceiveLen + 1;
                true ->
                    NewSendLen = SendLen + 1,
                    NewReceiveLen = ReceiveLen
            end,
            NewAccL = case IsAnonymous of
                    0 ->
                        case lib_role:get_role_show(OtherId) of
                            #ets_role_show{figure = Figure} ->
                            [{Code, Id, GoodsId, Num, IsAnonymous, Time, Thank, Figure}|AccL];
                        _ -> AccL
                        end;
                    _ ->
                        % OtherName = data_language:get(?LAN_MYSTERY_MAN),
                    [{Code, Id, GoodsId, Num, IsAnonymous, Time, Thank, #figure{}}|AccL]
                end;
        _ ->
            {NewSendLen, NewReceiveLen} = {SendLen, ReceiveLen},
            NewAccL = AccL
    end,
    pack_gift_record(L, {NewSendLen, NewReceiveLen}, ExpireTime, NewAccL).

%% 赠送礼物
send_gift(Player, ReceiverId, GoodsId, Num, IsAnonymous) ->
    #player_status{id = RoleId, figure = Figure} = Player,
    #figure{lv = RoleLv, vip = VipLv} = Figure,
    case send_gift_check(GoodsId, RoleLv, VipLv) of
        {true, #flower_gift_cfg{is_sell = IsSell} = GiftCfg} ->
            case lib_goods_api:cost_object_list(Player, [{?TYPE_GOODS, GoodsId, Num}], send_flower, "") of
                {true, NewPlayer} -> %% 东西足够
                    {NewPlayer1, OldFame, NewFame} = do_send_gift(NewPlayer, ReceiverId, Num, GiftCfg, IsAnonymous),
                    receive_flower_gift(RoleId, ReceiverId, GiftCfg, Num, IsAnonymous, OldFame, NewFame),
                    add_flower_record(RoleId, ReceiverId, GoodsId, Num, IsAnonymous, ?CODE_SEND_FLOWER),
                    lib_role_legion:trigger_task(NewPlayer1, ?MOD_FLOWER, 0),
                    custom_act_journey:trigger_act_task(RoleId, gift, 1),
                    {ok, NewPlayer3} = mate_logic:update_take_progress(NewPlayer1, [ReceiverId, ?TASK_TYPE_1]),
                    NewPlayer3;
                {false, _Res, NewPlayer} ->
                    %% 东西不够
                    case IsSell == 1 of
                        true ->
                            case sp_gift_check(RoleId, GoodsId) of
                                true ->
                                    case data_goods:get_goods_buy_price(GoodsId) of
                                        {0, 0} ->
                                            lib_server_send:send_to_uid(RoleId, pt_223, 22301, [?ERRCODE(err150_type_err), ReceiverId, 0, 0]),
                                            NewPlayer;
                                        {PriceType, Price} ->
                                            %% 能买就直接扣钱加好感度
                                            case calc_need_money(Player, GoodsId, Num, PriceType, Price) of
                                                {true, Money} ->
                                                    case lib_goods_api:cost_money(NewPlayer, PriceType, Money, send_flower, "") of
                                                        {1, NewPlayer1} ->
                                                            {NewPlayer2, OldFame, NewFame} = do_send_gift(NewPlayer1, ReceiverId, Num, GiftCfg, IsAnonymous),
                                                            receive_flower_gift(RoleId, ReceiverId, GiftCfg, Num, IsAnonymous, OldFame, NewFame),
                                                            %% 添加送礼记录
                                                            add_flower_record(RoleId, ReceiverId, GoodsId, Num, IsAnonymous, ?CODE_SEND_FLOWER),
                                                            %% 七日目标任务
                                                            % {ok, NewPlayer3} = lib_seven_days_goal:do_finish_task(NewPlayer2, ?MOD_FLOWER, 0, Num),
                                                            lib_role_legion:trigger_task(NewPlayer2, ?MOD_FLOWER, 0),
                                                            custom_act_journey:trigger_act_task(RoleId, gift, 1),
                                                            {ok, NewPlayer4} = mate_logic:update_take_progress(NewPlayer2, [ReceiverId, ?TASK_TYPE_1]),
                                                            NewPlayer4;
                                                        {_Errcode, NewPlayer1} ->
                                                            lib_server_send:send_to_uid(RoleId, pt_223, 22301, [?ERRCODE(goods_not_enough), ReceiverId, 0, 0]),
                                                            NewPlayer1
                                                    end;
                                                {false, ErrCode} ->
                                                    lib_server_send:send_to_uid(RoleId, pt_223, 22301, [ErrCode, ReceiverId, 0, 0]),
                                                    NewPlayer
                                            end
                                    end;
                                {false, ErrCode} ->
                                    lib_server_send:send_to_uid(RoleId, pt_223, 22301, [ErrCode, ReceiverId, 0, 0]),
                                    NewPlayer
                            end;
                        false -> %% 非出售道具 道具不足
                            lib_server_send:send_to_uid(RoleId, pt_223, 22301, [?ERRCODE(goods_not_enough), ReceiverId, 0, 0]),
                            NewPlayer
                    end
            end;
        {false, ErrCode} ->
            lib_server_send:send_to_uid(RoleId, pt_223, 22301, [ErrCode, ReceiverId, 0, 0]),
            Player
    end.

calc_need_money(Player, GoodsId, Num, _PriceType, Price) ->
    [{_, BagNum}] = lib_goods_api:get_goods_num(Player, [GoodsId]),
    if
        BagNum == 0 -> {true, round(Price*Num)};
        BagNum < Num -> {true, round(Price*(Num-BagNum))};
        true -> {false, ?FAIL}
    end.

sp_gift_check(RoleId, GoodsId) ->
    case is_sp_gift(GoodsId) of
        false ->
            true;
        _ ->
            GoodsCount = lib_daily:get_count(RoleId, ?MOD_FLOWER, 1, GoodsId),
            #base_flower_sp_gift{limit_count = CountCfg} = data_flower:get_sp_gift(GoodsId),
            if GoodsCount >= CountCfg ->
                    {false, ?ERRCODE(err223_sp_gift_limit_count)};
                true ->
                    true
            end
    end.

do_send_gift(Player, ReceiverId, Num, GiftCfg, IsAnonymous) ->
    #player_status{sid = Sid, id = RoleId, flower = RoleFlowerData, figure = Figure} = Player,
    #figure{name = RoleName} = Figure,
    #flower_gift_cfg{
        goods_id    = GoodsId,
        type        = GiftType,
        effect_type = EffectType,
        effect      = Effect,
        intimacy    = IntimacyPlus,
        fame        = FamePlus,
        is_tv       = IsTv
    } = GiftCfg,
    IntimacyAdd = round(IntimacyPlus*Num),
    FameAdd     = round(FamePlus*Num),
    %% 更新双方亲密度
    lib_relationship:update_intimacy_each_one(RoleId, ReceiverId, IntimacyAdd, ?INTIMACY_TYPE_PRESENT, [{GoodsId, Num}]),
    %% 飘字提示
    case lib_relationship:is_friend_on_dict(RoleId, ReceiverId) of
        true ->
            lib_task_api:friend_gift(Player),
            TipsBinData = lib_chat:make_tv(?MOD_FLOWER, 9, [FameAdd, IntimacyAdd]);
        false ->
            TipsBinData = lib_chat:make_tv(?MOD_FLOWER, 8, [FameAdd])
    end,
    lib_server_send:send_to_sid(Sid, TipsBinData),
    %% 发送传闻
    case IsTv > 0 of
        true ->
            ReceiverName = case lib_role:get_role_show(ReceiverId) of
                               #ets_role_show{figure = ReceiverFigure} -> ReceiverFigure#figure.name;
                               _ -> "???"
                           end,
            #ets_goods_type{goods_name = GoodsName} = data_goods_type:get(GoodsId),
            case IsAnonymous of
                0 ->
                    BinData = lib_chat:make_tv(?MOD_FLOWER, 6, [ReceiverName, RoleName, GoodsName]);
                _ ->
                    BinData = lib_chat:make_tv(?MOD_FLOWER, 7, [ReceiverName, GoodsName])
            end,
            lib_server_send:send_to_all(BinData);
        false -> skip
    end,
    %% 显示特效
    case EffectType of
        2 -> %% 双方特效
            {ok, FXBinData} = pt_110:write(11063, [Effect]),
            lib_server_send:send_to_uid(RoleId, FXBinData),
            lib_server_send:send_to_uid(ReceiverId, FXBinData);
        3 -> %% 全服特效
            {ok, FXBinData} = pt_110:write(11063, [Effect]),
            lib_server_send:send_to_all(FXBinData);
        _ -> skip
    end,
    %% 赠送方增加慷慨值
    NewFame = RoleFlowerData#flower.fame + FameAdd,
    db:execute(io_lib:format(?sql_update_fame, [NewFame, RoleId])),
    PreFameLv = get_fame_lv(RoleFlowerData#flower.fame),
    NewFameLv = get_fame_lv(NewFame),
    case PreFameLv =/= NewFameLv of
        true ->
            #fame_lv_cfg{attr = NewFameAttr} = data_flower:get_fame_lv_cfg(NewFameLv),
            NewPlayerTmp = Player#player_status{flower = RoleFlowerData#flower{fame = NewFame, attr = NewFameAttr}},
            NewPlayer = lib_player:count_player_attribute(NewPlayerTmp),
            lib_player:send_attribute_change_notify(NewPlayer, ?NOTIFY_ATTR);
        false -> NewPlayer = Player#player_status{flower = RoleFlowerData#flower{fame = NewFame}}
    end,
    %% 触发成就
    {ok, AchievePlayer} = lib_achievement_api:flower_send_event(NewPlayer, NewFame),
    %% 刷新排行榜
    mod_common_rank:refresh_common_rank(?RANK_TYPE_GENEROURS, {RoleId, NewFame}),

    %% 特殊礼品
    LastPlayer = sp_gift_trigger(AchievePlayer, ReceiverId, GoodsId, GiftType),

    LastPlayer1 = lib_activitycalen_api:role_success_end_activity(LastPlayer, ?MOD_FLOWER, 0, Num),

    {LastPlayer1, RoleFlowerData#flower.fame, NewFame}.

%% 普通礼品
sp_gift_trigger(Player, _ReceiverId, _GoodsId, 0) ->
    Player;
%% 特殊礼品
sp_gift_trigger(Player, ReceiverId, GoodsId, _GiftType) ->
    #player_status{id = RoleId, figure = #figure{name = RoleName}, flower = RoleFlower} = Player,
    #flower{sp_gift = SpGiftList} = RoleFlower,
    case is_sp_gift(GoodsId) of
        false -> Player;
        []    -> Player;
        #base_flower_sp_gift{
            my_back_reward = Rewards,
            my_day = LastDay1,
            friend_back_reward = FriendRewards,
            friend_day = LastDay2
        } ->
            Now = utime:unixtime(),
            NewSpGift = #sp_gift{
                key = {Now, RoleId},
                start_time = Now,
                day = LastDay1,
                goods_id = GoodsId,
                sender = RoleId,
                receive_times = [Now]
            },
            db_update_role_sp_gift(RoleId, NewSpGift),
            Rest = max(LastDay1-1, 0),
            if Rest == 0 ->
                    {Title, Content} = get_sp_gift_mail_format([1], sender);
                true ->
                    {Title, Content} = get_sp_gift_mail_format([1, Rest], sender)
            end,
            lib_mail_api:send_sys_mail([RoleId], Title, Content, Rewards),
            NewSpGiftList = lists:keystore({Now, RoleId}, #sp_gift.key, SpGiftList, NewSpGift),
            lib_daily:increment(RoleId, ?MOD_FLOWER, 1, GoodsId),
            receiver_get_sp_gift(ReceiverId, RoleId, RoleName, Now, GoodsId, FriendRewards, LastDay2),
            NewPlayer = Player#player_status{flower = RoleFlower#flower{sp_gift = NewSpGiftList}},
            pp_flower:handle(22308, NewPlayer, []),
            NewPlayer
    end.

get_sp_gift_mail_format([Index, Rest], sender) ->
    Title   = ?LAN_MSG(2230005),
    Content = uio:format(?LAN_MSG(2230006), [Index, Rest]),
    {Title, Content};
get_sp_gift_mail_format([Index], sender) ->
    Title = ?LAN_MSG(2230007),
    Content = uio:format(?LAN_MSG(2230008), [Index]),
    {Title, Content};
get_sp_gift_mail_format([RoleName, Index, Rest], receiver) ->
    Title = ?LAN_MSG(2230001),
    Content = uio:format(?LAN_MSG(2230002), [RoleName, Index, Rest]),
    {Title, Content};
get_sp_gift_mail_format([RoleName, Index], receiver) ->
    Title = ?LAN_MSG(2230003),
    Content = uio:format(?LAN_MSG(2230004), [RoleName, Index]),
    {Title, Content}.

is_sp_gift(GoodsId) ->
    AllSpGift = data_flower:get_all_sp_gift(),
    case lists:member(GoodsId, AllSpGift) of
        true -> data_flower:get_sp_gift(GoodsId);
        _    -> false
    end.

db_update_role_sp_gift(RoleId, SpGift) ->
    #sp_gift{
        start_time = StartTime, day = Day, goods_id = GoodsId,
        sender = Sender, receive_times = ReceiveTimeL
    } = SpGift,
    ReceiveTimeLBin = util:term_to_bitstring(ReceiveTimeL),
    db:execute(?sql_replace_sp_gift, [RoleId, StartTime, Sender, Day, GoodsId, ReceiveTimeLBin]),
    ok.

receiver_get_sp_gift(ReceiverId, Sender, SenderName, Now, GoodsId, Rewards, LastDay) ->
    NewSpGift = #sp_gift{
        start_time = Now, day = LastDay, sender = Sender, goods_id = GoodsId, receive_times = [Now]
    },
    Pid = misc:get_player_process(ReceiverId),
    case is_pid(Pid) andalso misc:is_process_alive(Pid) of
        true ->
            lib_player:apply_cast(ReceiverId, ?APPLY_CAST_SAVE, ?MODULE, role_receive_sp_gift, [NewSpGift, SenderName, Rewards]);
        _ -> %% 对方离线,直接处理
            Rest = max(LastDay-1, 0),
            if Rest == 0 ->
                    {Title, Content} = get_sp_gift_mail_format([SenderName, 1], receiver);
                true ->
                    {Title, Content} = get_sp_gift_mail_format([SenderName, 1, Rest], receiver)
            end,
            lib_mail_api:send_sys_mail([ReceiverId], Title, Content, Rewards),
            db_update_role_sp_gift(ReceiverId, NewSpGift)
    end.

role_receive_sp_gift(Player, SpGift, SenderName, Rewards) ->
    #player_status{id = RoleId, flower = RoleFlower} = Player,
    #flower{sp_gift = SpGiftList} = RoleFlower,
    #sp_gift{day = LastDay} = SpGift,
    NewSpGiftList = lists:keystore(SpGift#sp_gift.key, #sp_gift.key, SpGiftList, SpGift),
    NewRoleFlower = RoleFlower#flower{sp_gift = NewSpGiftList},
    Rest = max(LastDay-1, 0),
    if Rest == 0 ->
            {Title, Content} = get_sp_gift_mail_format([SenderName, 1], receiver);
        true ->
            {Title, Content} = get_sp_gift_mail_format([SenderName, 1, Rest], receiver)
    end,
    lib_mail_api:send_sys_mail([RoleId], Title, Content, Rewards),
    db_update_role_sp_gift(RoleId, SpGift),
    {ok, Player#player_status{flower = NewRoleFlower}}.


%% 获取对方魅力值(对方玩家进程)
get_charm(Player, Sid) ->
    #player_status{flower = Flower} = Player,
    Charm = Flower#flower.charm,
    lib_server_send:send_to_sid(Sid, pt_223, 22306, [Charm]).

%% 被砸鸡蛋(被砸玩家进程)
be_throwed_eggs(Player, EggId, RoleName, RoleSid, NewCount) ->
    #player_status{sid = Sid, id = PlayerId, flower = FlowerData} = Player,
    #flower_egg_cfg{egg_name = EggName, charm_value = CharmValue, effect = Effect} = data_flower:get_egg_cfg(EggId),
    %% 减少魅力值
    OldCharm = FlowerData#flower.charm,
    NewCharm = max(OldCharm - CharmValue, 0),
    NewFlower = FlowerData#flower{charm = NewCharm},
    %% 发提示
    lib_chat:send_TV({player, PlayerId}, ?MOD_FLOWER, 15, [RoleName, EggName, CharmValue]),
    %% 特效
    lib_server_send:send_to_sid(Sid, pt_110, 11063, [Effect]),
    if
        OldCharm > 0 ->
            lib_server_send:send_to_sid(RoleSid, pt_223, 22305, [?SUCCESS, NewCharm, NewCount]);
        true ->
            lib_server_send:send_to_sid(RoleSid, pt_223, 22300, [?ERRCODE(err223_player_charm_is_zero)])
    end,
    NewPlayer = Player#player_status{flower = NewFlower},
    {ok, NewPlayer}.

%% 玩家收到鲜花
receive_flower_gift(OtherId, ReceiverId, GiftCfg, Num, IsAnonymous, OldFame, NewFame) when is_integer(OtherId) ->
    #flower_gift_cfg{
        goods_id = GoodsId,
        charm = CharmPlus
    } = GiftCfg,
    ReceiverPid = misc:get_player_process(ReceiverId),
    case misc:is_process_alive(ReceiverPid) of
        true -> %% 在线跳到玩家进程处理
            lib_player:apply_cast(ReceiverPid, ?APPLY_CAST_SAVE, lib_flower, receive_flower_gift, [OtherId, GiftCfg, Num, IsAnonymous, OldFame, NewFame]);
        false -> %% 玩家不在线直接操作数据库
            NewRecordId = case catch mod_id_create:get_new_id(?FLOWER_GIFT_RECORD_ID_CREATE) of
                AutoId when is_integer(AutoId) -> AutoId;
                _ -> 0
            end,
            Now = utime:unixtime(),
            case db:get_row(io_lib:format(?sql_sel_role_flower_data, [ReceiverId])) of
                [PreCharm, PreFame, FlowerNum, PreWeekCharm, PreUpdateTime | _] ->
                    NewCharm = PreCharm + CharmPlus,
                    {NewWeekCharm, NewTime} = update_week_charm(PreWeekCharm, Now, PreUpdateTime, CharmPlus);
                _ ->
                    PreCharm = 0, NewCharm = CharmPlus, FlowerNum = 0,
                    NewWeekCharm = CharmPlus, PreFame = 0, NewTime = Now
            end,
            mod_common_rank:refresh_common_rank(?RANK_TYPE_CHARM_WEEK, {ReceiverId, NewCharm}),
            db:execute(?sql_replace_flower, [ReceiverId, FlowerNum, NewCharm, PreFame, NewWeekCharm, NewTime]),
            case NewRecordId > 0 of
                true ->
                    db:execute(io_lib:format(?sql_insert_flower_gift_record,
                     [NewRecordId, ReceiverId, OtherId, GoodsId, Num, IsAnonymous, utime:unixtime(), ?CODE_RECEIVE_FLOWER, 0]));
                _ -> skip
            end,
            %% 此时应在赠送者进程
            %% 通知赠送者
            case lib_relationship:get_rela_with_other_on_dict(OtherId, ReceiverId) of
                #rela{intimacy = Intimacy} -> ok;
                _ -> Intimacy = 0
            end,
            lib_server_send:send_to_uid(OtherId, pt_223, 22301, [?SUCCESS, ReceiverId, NewWeekCharm, Intimacy]),
            lib_log_api:log_flower(OtherId, ReceiverId, GoodsId, OldFame, NewFame, PreCharm, NewCharm),
            ok
    end;

%% 收到鲜花礼物(收礼物玩家进程)
receive_flower_gift(Player, OtherId, GiftCfg, Num, IsAnonymous, OldFame, NewFame) when is_record(Player, player_status) ->
    #player_status{id = RoleId, flower = RoleFlowerData} = Player,
    #flower_gift_cfg{
        goods_id = GoodsId,
        charm = CharmPlus
    } = GiftCfg,

    ReceiveFlowerRecord = get_flower_record_on_dict(RoleId),
    Code = ?CODE_RECEIVE_FLOWER,
    NowTime = utime:unixtime(),
    CharmAdd = round(CharmPlus*Num),

    NewRecordId =
    case catch mod_id_create:get_new_id(?FLOWER_GIFT_RECORD_ID_CREATE) of
        AutoId when is_integer(AutoId) -> AutoId;
            _ -> 0
    end,
    db:execute(io_lib:format(?sql_insert_flower_gift_record, [NewRecordId, RoleId, OtherId, GoodsId, Num, IsAnonymous, NowTime, Code, 0])),

    #player_status{flower = #flower{week_charm = NewWeekCharm}} = NewPlayer = lib_flower_api:add_charm(Player, CharmAdd),

    OneRecord = make_record(flower_gift_record, [NewRecordId, RoleId, OtherId, GoodsId, Num, IsAnonymous, NowTime, Code, 0]),
    NewReceiveFlowerRecord = [OneRecord|ReceiveFlowerRecord],
    save_flower_record_on_dict(NewReceiveFlowerRecord),

    %% 触发成就
    NewCharm = RoleFlowerData#flower.charm + CharmAdd,
    {ok, LastPlayer} = lib_achievement_api:flower_get_event(NewPlayer, NewCharm),
    %% 通知客户端收到新的鲜花礼物提示
    {ok, TipsBin} = pt_110:write(11016, [?MOD_FLOWER, ?RED_POINT_RECEIVE_FLOWER_GIFT, 1]),

    case lib_relationship:get_rela_with_other_on_dict(RoleId, OtherId) of
        #rela{intimacy = Intimacy} -> ok;
        _ -> Intimacy = 0
    end,
    %% 通知赠送者
    lib_server_send:send_to_uid(OtherId, pt_223, 22301, [?SUCCESS, RoleId, NewWeekCharm, Intimacy]),
    lib_server_send:send_to_uid(RoleId, TipsBin),
    %% 日志
    lib_log_api:log_flower(OtherId, RoleId, GoodsId, OldFame, NewFame, RoleFlowerData#flower.charm, NewCharm),
    %% 排行榜刷新
    mod_common_rank:refresh_common_rank(?RANK_TYPE_CHARM_WEEK, {RoleId, NewCharm}),
    {ok, LastPlayer}.

get_fame_lv(Fame) ->
    %% 这里获取到的ids列表是根据所需名誉降序排列的
    AllIds = data_flower:get_fame_lv_cfg_ids(),
    do_get_fame_lv(AllIds, Fame).

do_get_fame_lv([], _) -> 0;
do_get_fame_lv([Id | Ids], Fame) ->
    case data_flower:get_fame_lv_cfg(Id) of
        #fame_lv_cfg{fame = NeedFame} when Fame >= NeedFame -> Id;
        _ -> do_get_fame_lv(Ids, Fame)
    end.

get_fame_attr(Fame) ->
    case get_fame_lv(Fame) of
        Lv when Lv > 0 ->
            #fame_lv_cfg{attr = Attr} = data_flower:get_fame_lv_cfg(Lv),
            Attr;
        _ -> []
    end.
daily_timer(DelaySec) ->
    spawn(fun() ->
        util:multiserver_delay(DelaySec, lib_flower, clear, [])
    end).
clear() ->
    %% 清理过期的收礼记录
    ClearTime = utime:unixtime() - ?RECORD_VAILD_TIME,
    db:execute(io_lib:format(?sql_del_gift_record_out_time, [ClearTime])).

%% 添加送礼记录
add_flower_record(RoleId, ReceiverId, GoodsId, Num, IsAnonymous, Code) ->
    ReceiveFlowerRecord = get_flower_record_on_dict(RoleId),
    NewRecordId =
     case catch mod_id_create:get_new_id(?FLOWER_GIFT_RECORD_ID_CREATE) of
        AutoId when is_integer(AutoId) -> AutoId;
        _ -> 0
    end,
    OneRecord = make_record(flower_gift_record, [NewRecordId, RoleId, ReceiverId, GoodsId, Num, IsAnonymous, utime:unixtime(), Code, 0]),
    NewReceiveFlowerRecord = [OneRecord|ReceiveFlowerRecord],
    save_flower_record_on_dict(NewReceiveFlowerRecord),
    db:execute(io_lib:format(?sql_insert_flower_gift_record, [NewRecordId, RoleId, ReceiverId, GoodsId, Num, IsAnonymous, utime:unixtime(), Code, 0])).

check_new_flower_record(RoleId, LastLogoutTime) ->
    FlowerRecordList = get_flower_record_on_dict(RoleId),
    Fun = fun(#flower_gift_record{time = Time}) ->
        if
            Time >= LastLogoutTime-> %% 收到花的时间大于之前的时间
                true;
            true ->
                false
        end
    end,
    lists:any(Fun, FlowerRecordList).

thank_flower_sender(Player, Id) ->
    #player_status{id = RoleId, sid = Sid} = Player,
    FlowerRecordList = get_flower_record_on_dict(RoleId),
    case lists:keyfind(Id, #flower_gift_record.id, FlowerRecordList) of
        OneRecord = #flower_gift_record{thank = 0, code = ?CODE_RECEIVE_FLOWER} ->
            NewFlowerRecordList = lists:keystore(Id, #flower_gift_record.id, FlowerRecordList, OneRecord#flower_gift_record{thank = 1}),
            db:execute(io_lib:format(?sql_update_flower_gift_record, [1, Id])),
            save_flower_record_on_dict(NewFlowerRecordList),
            lib_server_send:send_to_sid(Sid, pt_223, 22309, [?SUCCESS, Id]);
        #flower_gift_record{thank = 1} ->
            lib_server_send:send_to_sid(Sid, pt_223, 22309, [?ERRCODE(err223_have_thanked), Id]);
        _A ->
            ?ERR("~p ~p", [Id, _A]),
            lib_server_send:send_to_sid(Sid, pt_223, 22309, [?FAIL, Id])
    end,
    ok.

%% ---------- 合法性检查 ------------

send_gift_check(GoodsId, RoleLv, VipLv) ->
    GoodsGiftCfg = data_flower:get_flower_gift_cfg(GoodsId),
    if
        not is_record(GoodsGiftCfg, flower_gift_cfg) ->
            {false, ?ERRCODE(config_err)};
        true ->
            #flower_gift_cfg{need_lv = NeedLv, need_vip = NeedVip} = GoodsGiftCfg,
            if RoleLv < NeedLv andalso VipLv < NeedVip ->
                    {false, ?ERRCODE(err223_dissatisfy_send_gift_condition)};
                true ->
                    {true, GoodsGiftCfg}
            end
    end.

check(_Player, []) ->
   true;
check(Player, [Check|CheckList]) ->
   case do_check(Player, Check) of
      true ->
         check(Player, CheckList);
      {false, ErrCode} ->
         {false, ErrCode}
   end.

do_check(_Player, {'check_cfg', EggId}) ->
    case data_flower:get_egg_cfg(EggId) of
        EggCfg when is_record(EggCfg, flower_egg_cfg) ->
            true;
        _ ->
            {false, ?MISSING_CONFIG}
    end;

do_check(_Player, {'check_online', Id}) ->
    Pid = misc:get_player_process(Id),
    case misc:is_process_alive(Pid) of
        true ->
            true;
        _ ->
            {false, ?ERRCODE(err223_player_not_online)}
    end;

do_check(Player, {'lv_limit', EggId}) ->
    Figure = Player#player_status.figure,
    Lv = Figure#figure.lv,
    #flower_egg_cfg{min_lv = MinLv} = data_flower:get_egg_cfg(EggId),
    if
        Lv >= MinLv ->
            true;
        true ->
            {false, ?ERRCODE(err223_lv_not_enough)}
    end;

do_check(Player, {'vip_limit', EggId}) ->
    Figure = Player#player_status.figure,
    VipLv = Figure#figure.vip,
    #flower_egg_cfg{vip_lv = MinVipLv} = data_flower:get_egg_cfg(EggId),
    if
        VipLv >= MinVipLv ->
            true;
        true ->
            {false, ?ERRCODE(err223_vip_not_enough)}
    end;

do_check(Player, {'check_enough_times', EggId}) ->
    UseTime = lib_daily:get_count(Player#player_status.id, ?MOD_FLOWER, EggId),
    #flower_egg_cfg{limit_time = LimitTime} = data_flower:get_egg_cfg(EggId),
    if
        UseTime < LimitTime orelse LimitTime == 0 ->
            true;
        true ->
            {false, ?ERRCODE(err223_num_not_enough)}
    end;

%% 容错
do_check(_Player, CheckMsg) ->
   ?ERR("bad match do_check:~p~n",[CheckMsg]),
   {false, ?FAIL}.
