%%-----------------------------------------------------------------------------
%% @Module  :       lib_smashed_egg
%% @Author  :       Czc
%% @Email   :       389853407@qq.com
%% @Created :       2018-03-02
%% @Description:    砸蛋
%%-----------------------------------------------------------------------------
-module(lib_smashed_egg).

-include("smashed_egg.hrl").
-include("custom_act.hrl").
-include("common.hrl").
-include("errcode.hrl").
-include("def_fun.hrl").
-include("server.hrl").
-include("goods.hrl").
-include("def_module.hrl").
-include("def_goods.hrl").
-export([
    init/1
    , check_act/4
    , make_role_info/5
    , save_role_info/1
    , save_role_reward_info/3
    , smashed_one/7
    , smashed_more/10
    , send_tv/3
    , filter_unreceive_reward/3
    , auto_send_unreceive_reward/2
    , receive_reward/5
    , get_free_time/2
    ]).

-export([
    pack_show_list/1
    , pack_eggs_list/1
    , pack_record_list/1
    , pack_cumulate_reward_list/3
    ]).

-export([
    reload_file/0,
    send_cfg/1,
    get_reward_ids_by_show_tag/2,
    is_all_smashed/1
    ]).

%% 初始化
init(State) ->
    Sql = io_lib:format(?sql_select_smashed_egg, []),
    List = db:get_all(Sql),
    F = fun([RoleId, SubType, OnlineTime, LastFreeSmashedTime, RefreshTimes, AddRefreshTimes, FreeSmashedTimes, SmashedTimes, EggsStr, CumulateRewardStr, ShowIdsStr, Utime], AccMap) ->
        ShowIds = util:bitstring_to_term(ShowIdsStr),
        CumulateRewardL = util:bitstring_to_term(CumulateRewardStr),
        EggsL = util:bitstring_to_term(EggsStr),
        Sql2 = io_lib:format(?sql_select_smashed_egg_reward, [RoleId, SubType]),
        List2 = db:get_all(Sql2),
        F2 = fun([GoodsId, Num], RewardList) ->
                [{?TYPE_BIND_GOODS, GoodsId, Num} | RewardList]
        end,
        RewardList = ulists:object_list_merge(lists:foldl(F2, [], List2)),
        RoleInfo = #role_info{
            key = {?CUSTOM_ACT_TYPE_SMASHED_EGG, SubType},
            role_id = RoleId,
            lfree_smashed_time = LastFreeSmashedTime,
            free_smashed_times = FreeSmashedTimes,
            online_time = OnlineTime,
            add_refresh_times = AddRefreshTimes,
            refresh_times = RefreshTimes,
            smashed_times = SmashedTimes,
            eggs = [#egg_info{id = Id, status = Status, goods_id = GoodsId, goods_num = GoodsNum, effect = Effect} || {Id, Status, GoodsId, GoodsNum, Effect} <- EggsL],
            cumulate_reward = CumulateRewardL,
            show_ids = ShowIds,
            utime = Utime,
            reward_list = RewardList
        },
        RoleInfoL = maps:get(RoleId, AccMap, []),
        NewRoleInfoL = lists:keystore({?CUSTOM_ACT_TYPE_SMASHED_EGG, SubType}, #role_info.key, RoleInfoL, RoleInfo),
        maps:put(RoleId, NewRoleInfoL, AccMap)
    end,
    RoleMap = lists:foldl(F, #{}, List),
    State#act_state{role_map = RoleMap}.

%% 活动通常检测
check_act(Type, SubType, RoleLv, NowTime) ->
    case lib_custom_act_util:get_custom_act_open_info(Type, SubType) of
        #act_info{etime = Etime} = ActInfo when NowTime < Etime -> %% 开启时间
            case lib_custom_act_util:get_act_cfg_info(Type, SubType) of
                #custom_act_cfg{
                    condition = Condition
                } -> %% 配置检测
                    case lib_custom_act_check:check_act_condtion([role_lv, free_refresh_times, smashed_times_lim], Condition) of
                        [OpenLv, MaxFreeSmashedTimes, SmashedTimesLim] when RoleLv >= OpenLv -> %% 条件检测
                            {true, ActInfo, MaxFreeSmashedTimes, SmashedTimesLim};
                        [_OpenLv, _FreeSmashedTimes, _SmashedTimesLim] -> {false, ?ERRCODE(lv_limit)};
                        _ -> {false, ?ERRCODE(err_config)}
                    end;
                _ -> {false, ?ERRCODE(err_config)}
            end;
        false -> {false, ?ERRCODE(err331_act_closed)}
    end.

%% 新建玩家记录
make_role_info(Type, SubType, RoleId, _WorldLv, NowTime) ->
    % AllShowIds = get_reward_ids_by_show_tag(WorldLv, 1),
    % SortList = ulists:list_shuffle(AllShowIds),
    % ShowIds = lists:sublist(SortList, ?SHOW_BEST_COUNT),
    % ShowIds = lists:sublist(SortList, ?SHOW_BEST_COUNT),
    RoleInfo = #role_info{
        key = {Type, SubType},
        role_id = RoleId,
        eggs = [#egg_info{id = Index} || Index <- lists:seq(1, ?EGG_NUM)],
        % show_ids = ShowIds,
        utime = NowTime
    },
    save_role_info(RoleInfo),
    RoleInfo.

%% 保存玩家记录到数据库
save_role_info(RoleInfo) ->
    #role_info{
        key = {_Type, SubType},
        role_id = RoleId,
        online_time = OnlineTime,
        lfree_smashed_time = LastFreeSmashedTime,
        add_refresh_times = AddRefreshTimes,
        refresh_times = RefreshTimes,
        free_smashed_times = FreeSmashedTimes,
        smashed_times = SmashedTimes,
        eggs = EggsL,
        cumulate_reward = CumulateRewardL,
        show_ids = ShowIds,
        utime = Utime
    } = RoleInfo,
    EggArgs = [{Id, Status, GoodsId, GoodsNum, Effect} || #egg_info{id = Id, status = Status, goods_id = GoodsId, goods_num = GoodsNum, effect = Effect} <- EggsL],
    Sql = io_lib:format(?sql_save_smashed_egg,
        [RoleId, SubType, OnlineTime, LastFreeSmashedTime, RefreshTimes, AddRefreshTimes, FreeSmashedTimes, SmashedTimes, util:term_to_string(EggArgs), util:term_to_string(CumulateRewardL), util:term_to_string(ShowIds), Utime]),
    db:execute(Sql).

%% 保存玩家奖励到数据库
save_role_reward_info(RoleId, SubType, RewardL) ->
    F = fun({_Type, GoodsId, Num}, SqlArgsTmp) ->
        [[RoleId, SubType, GoodsId, Num] | SqlArgsTmp]
    end,
    SqlArgsTmp = lists:foldl(F, [], RewardL),
    SqlArgs = to_sql_string(SqlArgsTmp, []),
    Sql = lists:concat([?sql_save_smashed_egg_reward, SqlArgs]),
    db:execute(Sql).

%% 砸一个蛋
smashed_one(_RoleId, RoleName, WorldLv, NowTime, Index, EggsL, RecordL) ->
    #goods_reward_cfg{
        goods_id = GoodsId, goods_num = GoodsNum,
        is_tv = IsTv, effect = Effect
    } = rand_reward(WorldLv),
    NewEggInfo = #egg_info{
        id = Index, status = ?HAS_SMASHED,
        goods_id = GoodsId, goods_num = GoodsNum, effect = Effect
    },
    NewEggsL = lists:keystore(Index, #egg_info.id, EggsL, NewEggInfo),
    NewRecordL = lists:sublist([{RoleName, GoodsId, GoodsNum, NowTime}|RecordL], ?RECORD_LEN),
    NewTvArgs = ?IF(IsTv == 1, [{GoodsId, GoodsNum}], []),
    {NewEggsL, NewRecordL, NewTvArgs, [{?TYPE_BIND_GOODS, GoodsId, GoodsNum}], [{Index, GoodsId, GoodsNum}]}.

%% 一键开蛋
smashed_more([], _RoleId, _RoleName, _WorldLv, _NowTime, RecordL, TvArgs, RewardL, NewEggsL, SmashedResultL) ->
    NewRecordL = lists:sublist(RecordL, ?RECORD_LEN),
    NewRewardL = ulists:object_list_merge(RewardL),
    {lists:reverse(NewEggsL), NewRecordL, TvArgs, NewRewardL, SmashedResultL};
smashed_more([EggInfo|EggsL], RoleId, RoleName, WorldLv, NowTime, RecordL, TvArgs, RewardL, NewEggsL, SmashedResultL) ->
    case EggInfo of
        #egg_info{id = Id, status = ?NOT_SMASHED} -> %% 还没咋开的蛋
            #goods_reward_cfg{
                goods_id = GoodsId, goods_num = GoodsNum,
                is_tv = IsTv, effect = Effect
            } = rand_reward(WorldLv), %% 随机奖励
            NewEggInfo = EggInfo#egg_info{
                status = ?HAS_SMASHED, goods_id = GoodsId,
                goods_num = GoodsNum, effect = Effect
            },
            NewTvArgs = ?IF(IsTv == 1, [{GoodsId, GoodsNum}|TvArgs], TvArgs),
            NewRewardL = [{?TYPE_BIND_GOODS, GoodsId, GoodsNum}|RewardL],
            smashed_more(EggsL, RoleId, RoleName, WorldLv, NowTime, [{RoleName, GoodsId, GoodsNum, NowTime}|RecordL], NewTvArgs, NewRewardL, [NewEggInfo|NewEggsL], [{Id, GoodsId, GoodsNum}|SmashedResultL]);
        _ ->
            smashed_more(EggsL, RoleId, RoleName, WorldLv, NowTime, RecordL, TvArgs, RewardL, [EggInfo|NewEggsL], SmashedResultL)
    end.

%% 飘字广播
send_tv([], _RoleId, _RoleName) -> skip;
send_tv([T|TvArgs], RoleId, RoleName) ->
    case T of
        {GoodsId, _GoodsNum} ->
            _GoodsColor = data_goods:get_goods_color(GoodsId),
            ok;
            % lib_chat:send_TV({all}, ?MOD_AC_CUSTOM, urand:rand(1, 2), [RoleName, GoodsColor, GoodsId, GoodsNum]);
        _ -> skip
    end,
    send_tv(TvArgs, RoleId, RoleName).

%% 随机奖励
rand_reward(WorldLv) ->
    AllRewardIds = get_all_reward_ids(WorldLv),
    AllReward = lists:foldl(fun(OneId, RewardTemp) ->
        case data_smashed_egg:get_egg_reward(OneId) of
            OneReward when is_record(OneReward, goods_reward_cfg) ->
                [{OneReward#goods_reward_cfg.weights, OneReward}|RewardTemp];
            _ -> RewardTemp
        end
    end, [], AllRewardIds),
    urand:rand_with_weight(AllReward).

pack_show_list(ShowIds) ->
    pack_show_list(ShowIds, []).

pack_show_list([], Result) -> Result;
pack_show_list([T|L], Result) ->
    case data_smashed_egg:get_egg_reward(T) of
        #goods_reward_cfg{
            goods_id = GoodsId,
            goods_num = GoodsNum,
            effect = Effect
        } ->
            pack_show_list(L, [{GoodsId, GoodsNum, Effect}|Result]);
        _ ->
            pack_show_list(L, Result)
    end.

pack_eggs_list(EggsL) ->
    pack_eggs_list(EggsL, []).

pack_eggs_list([], Result) -> Result;
pack_eggs_list([T|L], Result) ->
    case T of
        #egg_info{
            id = Id,
            status = Status,
            goods_id = GoodsId,
            goods_num = GoodsNum,
            effect = Effect
        } ->
            pack_eggs_list(L, [{Id, Status, GoodsId, GoodsNum, Effect}|Result]);
        _ ->
            pack_eggs_list(L, Result)
    end.

pack_record_list(RecordL) -> RecordL.

pack_cumulate_reward_list(SmashedTimes, WorldLv, CumulateRewardL) ->
    AllTimesL = get_all_cumulate_reward_times(WorldLv),
    F = fun(Times, Acc) ->
        #cumulate_reward_cfg{times = Times, reward = RewardL} = data_smashed_egg:get_cumulate_reward(Times, WorldLv),
        case lists:member(Times, CumulateRewardL) of
            true -> ReceiveStatus = 2;
            _ ->
                case SmashedTimes >= Times of
                    true -> ReceiveStatus = 1;
                    _ -> ReceiveStatus = 0
                end
        end,
        [{Times, RewardL, ReceiveStatus}|Acc]
    end,
    lists:foldl(F, [], AllTimesL).

%% 筛选出未领取的累计奖励
filter_unreceive_reward(SmashedTimes, WorldLv, CumulateRewardL) ->
    AllTimesL = get_all_cumulate_reward_times(WorldLv),
    F = fun(Times, Acc) ->
        #cumulate_reward_cfg{times = Times, reward = RewardL} = data_smashed_egg:get_cumulate_reward(Times, WorldLv),
        case lists:member(Times, CumulateRewardL) of
            false ->
                case SmashedTimes >= Times of
                    true -> [RewardL|Acc];
                    _ -> Acc
                end;
            _ -> Acc
        end
    end,
    lists:foldl(F, [], AllTimesL).

%% 发送未领取的奖励
auto_send_unreceive_reward([], _) -> skip;
auto_send_unreceive_reward([{RoleId, RoleInfoL}|L], ActInfoL) ->
    F = fun(T, Acc) ->
        case T of
            #role_info{key = {_Type, SubType} = Key, smashed_times = SmashedTimes, cumulate_reward = CumulateRewardL, reward_list = RewardList} ->
                case lists:keyfind(Key, #act_info.key, ActInfoL) of
                    #act_info{wlv = WorldLv} ->
                        RewardL = filter_unreceive_reward(SmashedTimes, WorldLv, CumulateRewardL),
                        if
                            RewardList =/= [] ->
                                db:execute(io_lib:format(?sql_delete_smashed_reward, [RoleId, SubType])),
                                lib_log_api:log_receive_smashed_egg_reward(RoleId, SubType, RewardList),
                                RewardList ++ RewardL ++ Acc;
                            true ->
                                RewardL ++ Acc
                        end;
                    _ -> Acc
                end;
            _ -> Acc
        end
    end,
    AllRewardL = lists:foldl(F, [], RoleInfoL),
    case AllRewardL =/= [] of
        true ->
            LastAllRewardL = ulists:object_list_merge(AllRewardL),
            lib_mail_api:send_sys_mail([RoleId], ?MOD_AC_CUSTOM, ?CUSTOM_ACT_TYPE_SMASHED_EGG, utext:get(3310006), utext:get(3310007), LastAllRewardL),
            timer:sleep(100);
        false -> skip
    end,
    auto_send_unreceive_reward(L, ActInfoL).

get_all_reward_ids(WorldLv) ->
    AllIds = data_smashed_egg:get_all_reward_ids(),
    [Id || {MinWLv, MaxWLv, Id} <- AllIds, WorldLv >= MinWLv, WorldLv =< MaxWLv].

get_reward_ids_by_show_tag(WorldLv, ShowTag) ->
    AllIds = data_smashed_egg:get_reward_ids_by_show_tag(ShowTag),
    [Id || {MinWLv, MaxWLv, Id} <- AllIds, WorldLv >= MinWLv, WorldLv =< MaxWLv].

get_all_cumulate_reward_times(WorldLv) ->
    AllIds = data_smashed_egg:get_all_cumulate_reward_times(),
    [Times || {MinWLv, MaxWLv, Times} <- AllIds, WorldLv >= MinWLv, WorldLv =< MaxWLv].

%% 领取奖励（玩家进程）
receive_reward(PS, Type, SubType, GoodsId, RewardList) ->
    if
        GoodsId == 0 -> %% 领取全部
            NewRewardList = RewardList;
        true ->
            case lists:keyfind(GoodsId, 2, RewardList) of
                {GoodsType, GoodsId, Num} ->
                    NewRewardList = [{GoodsType, GoodsId, Num}];
                _ ->
                    NewRewardList = []
            end
    end,
    if
        NewRewardList == [] -> %% 奖励为空则不作操作
            NewPS = PS;
        true ->
            case lib_goods_api:can_give_goods(PS, NewRewardList) of
                true ->
                    Produce = #produce{type = smashed_egg, title = utext:get(3310008), content = utext:get(204), reward = NewRewardList, remark = "smashed_egg"},
                    mod_smashed_egg:clean_player_reward(PS#player_status.id, Type, SubType, GoodsId),
                    %% 日志
                    lib_log_api:log_receive_smashed_egg_reward(PS#player_status.id, SubType, NewRewardList),
                    NewPS = lib_goods_api:send_reward(PS, Produce),
                    lib_server_send:send_to_sid(PS#player_status.sid, pt_331, 33125, [?SUCCESS]);
                _ -> %% 背包空间不足
                    NewPS = PS,
                    lib_server_send:send_to_sid(PS#player_status.sid, pt_331, 33100, [?ERRCODE(err150_no_cell)])
            end
    end,
    {ok, NewPS}.

to_sql_string([V], Result) ->
    One = to_sql_string_helper(V, []),
    lists:concat(["(", One, ")"| Result]);
to_sql_string([V|T], Result) ->
    One = to_sql_string_helper(V, []),
    to_sql_string(T, [", (", One, ")"|Result]).

to_sql_string_helper([H], Result) ->
    lists:concat(lists:reverse(["'", uio:thing_to_string(H), "'"| Result]));
to_sql_string_helper([H|T], Result) ->
    to_sql_string_helper(T, ["', ", uio:thing_to_string(H), "'"| Result]).

%% 获取免费砸蛋次数
get_free_time(RealOnlineTime, FreeSmashedTimes) ->
    AllTimes = data_smashed_egg:get_free_time(),
    F = fun(Times, RealTimes) ->
        NeedTime = data_smashed_egg:get_free_need_oltime(Times),
        if
            NeedTime =< RealOnlineTime -> Times;
            true -> RealTimes
        end
    end,
    RealTimes = lists:foldl(F, 0, AllTimes),
    max(RealTimes - FreeSmashedTimes, 0).

get_cfg() ->
    AllReward = data_smashed_egg:get_all_reward_ids(),
    Fun1 = fun({MinWLv, MaxWLv, RewardId}, GoodsRewardCfgList) ->
        #goods_reward_cfg{goods_id=GoodsId,goods_num=GoodsNum,effect=Effect,is_rare=IsRare} = data_smashed_egg:get_egg_reward(RewardId),
        [{RewardId, MinWLv, MaxWLv, GoodsId, GoodsNum, Effect, IsRare}|GoodsRewardCfgList]
    end,
    GoodsRewardCfgList = lists:foldl(Fun1, [], AllReward),
    AllOnlineTime = data_smashed_egg:get_free_time(),
    Fun2 = fun(Times, FreeSmashedTimeCfgList) ->
        Time = data_smashed_egg:get_free_need_oltime(Times),
        [{Times, Time}|FreeSmashedTimeCfgList]
    end,
    FreeSmashedTimeCfgList = lists:foldl(Fun2, [], AllOnlineTime),
    {ok, Bin} = pt_331:write(33119, [GoodsRewardCfgList, FreeSmashedTimeCfgList]),
    Bin.

send_cfg(Sid) ->
    Bin = get_cfg(),
    lib_server_send:send_to_sid(Sid, Bin).

reload_file() ->
    Bin = get_cfg(),
    lib_server_send:send_to_all(Bin).

is_all_smashed(Eggs) ->
    F = fun(Status) -> Status == ?HAS_SMASHED end,
    lists:all(F, [Status || #egg_info{status = Status} <- Eggs]).
