%% ------------------------------------
%% desc:唤神检查
%% module:god_check.erl
%% author:hh
%% time:20/07/13
%% ------------------------------------

-module(god_check).

-export([
    check_god_active/2
    , check_god_star_up/2
    , check_god_lv_up/5
    , check_god_skill_up/2
    , check_god_equip/5
    , check_god_equip_remove/4
    , check_god_equip_upgrade/3
    , check_god_front/3
    , pos_is_unlock_by_suit/2
    , check_god_summon/3
    , check_god_lottery/3
]).

-include("server.hrl").
-include("god.hrl").
-include("errcode.hrl").
-include("attr.hrl").
-include("goods.hrl").
-include("def_goods.hrl").
-include("figure.hrl").
-include("common.hrl").
-include("dungeon.hrl").
-include("def_module.hrl").

%% 唤神激活检查
check_god_active(Player, GodId) ->
    #player_status{role_god = RoleGod} = Player,
    IsActive = lists:keymember(GodId, #god.id, RoleGod#role_god.god_info),
    GodConfig = data_god:get_god_info(GodId, 0),
    if
        not is_record(GodConfig, base_god_info) ->
            {false, ?MISSING_CONFIG};
        IsActive ->
            {false, ?ERRCODE(err173_have_active_god)};
        true ->
            #base_god_info{cost = Cost, skills = Skills} = GodConfig,
            {true, Cost, #god{id = GodId, skills = Skills}}
    end.


%% 唤神升星检查
check_god_star_up(Player, GodId) ->
    #player_status{role_god = RoleGod} = Player,
    God = lists:keyfind(GodId, #god.id, RoleGod#role_god.god_info),
    if
        not God ->
            {false, ?ERRCODE(err173_have_not_active)};
        true ->
            NewStar = God#god.star + 1,
            Config = data_god:get_god_info(GodId, NewStar),
            if
                not is_record(Config, base_god_info) ->
                    {false, ?ERRCODE(err173_god_star_max)};
                true ->
                    if God#god.lv < Config#base_god_info.need_lv ->
                        {false, ?ERRCODE(err173_god_lv_not_satisfy)};
                        true ->
                            {true, Config#base_god_info.cost, God#god.star, God#god{star = NewStar}}
                    end
            end
    end.

%% 升级检查
check_god_lv_up(Player, GodId, UpType, GoodsId, GoodsNum) ->
    #player_status{role_god = RoleGod, id = RoleId} = Player,
    God = lists:keyfind(GodId, #god.id, RoleGod#role_god.god_info),
    if
        not God ->
            {false, ?ERRCODE(err173_have_not_active)};
        true ->
            #god{lv = OldLv, exp = Exp} = God,
            Config = data_god:get_god_lv_exp(GodId, OldLv + 1),
            % ?ERR("~p ~p ~p", [GodId, Lv, Config]),
            if
                not is_integer(Config) orelse Config == 0 ->
                    {false, ?ERRCODE(err173_god_lv_max)};
                true ->
                    GoodsIdList = data_god:get_kv(lv_up_goods),
                    case UpType == 1 of
                        true ->
                            {ExpTemp, Cost} = calc_goods_to_cost(GoodsIdList, RoleId, Config, Exp, []);
                        false ->
                            case lists:keyfind(GoodsId, 1, GoodsIdList) of
                                {_, GoodsExp} ->
                                    ExpTemp = Exp + GoodsExp * GoodsNum,
                                    Cost = [{?TYPE_GOODS, GoodsId, GoodsNum}];
                                _ ->
                                    ExpTemp = 0,
                                    Cost = []
                            end
                    end,
                    if Cost =/= [] ->
                        Left = ExpTemp - Config,
                        God1 = case Left >= 0 of
                                   true ->
                                       Change = true,
                                       god_logic:do_god_upgrade(God#god{lv = OldLv + 1, exp = Left});
                                   false ->
                                       Change = false,
                                       God#god{exp = ExpTemp}
                               end,
                        {ok, Cost, God1, Change, God};
                        true ->
                            {false, ?GOODS_NOT_ENOUGH}
                    end
            end
    end.

%% 计算一键升级扣除物品
calc_goods_to_cost([], _, _, Exp, GoodsCost) -> {Exp, GoodsCost};
calc_goods_to_cost([{GoodsId, AddExp} | T], RoleId, NeedExp, Exp, GoodsCost) ->
    [{_, GoodsHave} | _] = lib_goods_api:get_goods_num(RoleId, [GoodsId]),
    case GoodsHave > 0 of
        true ->
            UpgradeNeed = max(util:ceil((NeedExp - Exp) / AddExp), 1),
            ToCost = min(GoodsHave, UpgradeNeed),
            ExpTemp = Exp + AddExp * ToCost,
            GoodsCostTemp = [{?TYPE_GOODS, GoodsId, ToCost} | GoodsCost],
            case ExpTemp >= NeedExp of
                true ->
                    {ExpTemp, GoodsCostTemp};
                false ->
                    calc_goods_to_cost(T, RoleId, NeedExp, ExpTemp, GoodsCostTemp)
            end;
        false ->
            calc_goods_to_cost(T, RoleId, NeedExp, Exp, GoodsCost)
    end.

%% 唤神技能升级检查
check_god_skill_up(Player, GodId) ->
    #player_status{role_god = RoleGod} = Player,
    God = lists:keyfind(GodId, #god.id, RoleGod#role_god.god_info),
    if
        not God ->
            {false, ?ERRCODE(err173_have_not_active)};
        true ->
            #god{skills = Skills, star = Star} = God,
            GodConfig = data_god:get_god_info(GodId, Star),
            % SkillExist = lists:keyfind(SkillId, 1, Skills),
            Cost = data_god:get_kv(skill_up_cost),
            if
                not is_record(GodConfig, base_god_info) ->
                    {false, ?MISSING_CONFIG};
            % not SkillExist ->
            %     {false, ?ERRCODE(err173_god_skill_not_exist)};
                Cost == [] ->
                    {false, ?MISSING_CONFIG};
                true ->
                    Max = GodConfig#base_god_info.skill_max,
                    CanUp = [{Id, Lv} || {Id, Lv} <- Skills, Lv < Max],
                    if
                        CanUp == [] ->
                            {false, ?ERRCODE(err173_god_skill_lv_max)};
                        true ->
                            {UpSkillId, NowLv} = urand:list_rand(CanUp),
                            NewSkillInfo = {UpSkillId, NowLv + 1},
                            NewSkills = lists:keyreplace(UpSkillId, 1, Skills, NewSkillInfo),
                            {true, Cost, God#god{skills = NewSkills}, NewSkillInfo}
                    end
            end
    end.

%% 唤神装备检查
check_god_equip(Player, GodId, EquipPos, GoodsId, GoodsStatus) ->
    #player_status{role_god = RoleGod, id = RoleId} = Player,
    #goods_status{dict = GoodsDict} = GoodsStatus,
    #role_god{god_info = GodInfo} = RoleGod,
    IsEquipPos = lists:member(EquipPos, ?DEFAULT_EQUIP_POS),
    God = lists:keyfind(GodId, #god.id, GodInfo),
    GoodsInfo = lib_goods_util:get_goods(GoodsId, GoodsDict, ?GOODS_LOC_GOD_BAG),
    if
        not IsEquipPos ->
            {false, ?ERRCODE(err173_god_equip_pos_error)};
        not God ->
            {false, ?ERRCODE(err173_have_not_active)};
        not is_record(GoodsInfo, goods) ->
            {false, ?ERRCODE(err150_no_goods)};
        true ->
            if GoodsInfo#goods.location =/= ?GOODS_LOC_GOD_BAG ->
                {false, ?ERRCODE(err150_location_err)};
                GoodsInfo#goods.subtype =/= EquipPos ->
                    {false, ?ERRCODE(err150_type_err)};
                true ->
                    GodEquips = lib_goods_util:get_goods_list_by_type(RoleId, ?GOODS_LOC_GOD_EQUIP, ?GOODS_TYPE_GOD_EQUIP, GoodsDict),
                    Cell = GodId * ?CELL_OFFSET + EquipPos,
                    OldEquip = lists:keyfind(Cell, #goods.cell, GodEquips),
                    {ok, GoodsInfo, OldEquip, Cell, God}
            end
    end.

%% 唤神装备卸下检查
check_god_equip_remove(Player, GodId, Pos, GoodsStatus) ->
    #player_status{role_god = RoleGod, id = RoleId} = Player,
    God = lists:keyfind(GodId, #god.id, RoleGod#role_god.god_info),
    NullCellNum = lib_goods_api:get_cell_num(RoleId, ?GOODS_LOC_GOD_BAG),
    if
        not is_record(God, god) ->
            {false, ?ERRCODE(err173_have_not_active)};
        NullCellNum =< 0 ->
            {false, ?ERRCODE(err159_5_bag_not_enough)};
        true ->
            PosCell = GodId * ?CELL_OFFSET + Pos,
            GodEquips = lib_goods_util:get_goods_list_by_type(RoleId, ?GOODS_LOC_GOD_EQUIP, ?GOODS_TYPE_GOD_EQUIP, GoodsStatus#goods_status.dict),
            GoodsInfo = lists:keyfind(PosCell, #goods.cell, GodEquips),
            if
                not is_record(GoodsInfo, goods) ->
                    {false, ?ERRCODE(err150_no_goods)};
                true ->
                    {ok, GoodsInfo, God}
            end
    end.

%% 唤神装备升级
check_god_equip_upgrade(GoodsId, CostList0, GoodsStatus) ->
    GoodsDict = GoodsStatus#goods_status.dict,
    GoodsInfo = lib_goods_util:get_goods(GoodsId, GoodsDict, ?GOODS_LOC_GOD_EQUIP),
    GoodsInfo1 = lib_goods_util:get_goods(GoodsId, GoodsDict, ?GOODS_LOC_GOD_BAG),
    NewGoodsInfo = check_goods_exist([GoodsInfo, GoodsInfo1]),
    CostList = lists:keydelete(GoodsId, 1, CostList0),
    if
        not is_record(NewGoodsInfo, goods) ->
            {false, ?ERRCODE(err150_no_goods)};
        NewGoodsInfo#goods.type =/= ?GOODS_TYPE_GOD_EQUIP ->
            {false, ?ERRCODE(err150_type_err)};
        CostList == [] ->
            {false, ?FAIL};
        true ->
            OldLv = god_logic:get_god_equip_lv(NewGoodsInfo#goods.extra_data),
            Next = data_god:get_god_equip_lv_exp(NewGoodsInfo#goods.color, OldLv + 1),
            if
                (not is_integer(Next)) orelse Next =< 0 ->
                    {false, ?ERRCODE(err173_god_equip_lv_max)};
                true ->
                    GoodsList = lib_goods_check:combine_goods_num_list(CostList),
                    case god_logic:calc_cost_list(GoodsList, GoodsStatus, 0, []) of
                        {false, Err} ->
                            {false, Err};
                        {AddExp, ToCost} ->
                            {ok, NewGoodsInfo, AddExp, ToCost}
                    end
            end
    end.

check_goods_exist([]) -> false;
check_goods_exist([GoodsInfo | Rest]) ->
    if
        is_record(GoodsInfo, goods) ->
            GoodsInfo;
        true ->
            check_goods_exist(Rest)
    end.

%% 唤神上阵检查
check_god_front(Player, GodId, Pos) ->
    #player_status{role_god = RoleGod} = Player,
    #role_god{unlock = Unlock, god_info = GodInfo} = RoleGod,
    God = lists:keyfind(GodId, #god.id, GodInfo),
    if
        not God ->
            {false, ?ERRCODE(err173_have_not_active)};
        God#god.pos == Pos ->
            {false, ?ERRCODE(err173_god_pos_repeat)};
        true ->
            OldGod = lists:keyfind(Pos, #god.pos, GodInfo),
            Res = if
                      ?IS_PRIMARY_GOD(Pos) ->    % 上阵主神位
                          pos_is_unlock(GodInfo, Unlock, Pos);
                      ?IS_SECONDARY_GOD(Pos) ->  % 上阵援助位
                          secondary_pos_is_unlock(GodInfo, God, Pos);
                      true -> % 下阵
                          #god{pos = OldPos} = God,
                          if
                              ?IS_PRIMARY_GOD(OldPos) -> % 主战
                                  %% 没有辅助位才能下阵
                                  F = fun(#god{pos = GodPos}) ->
                                      ?IS_THE_SECONDARY_GOD(GodPos, OldPos) end,
                                  case lists:any(F, GodInfo) of
                                      true ->
                                          {false, ?ERRCODE(err173_need_off_help_god)};
                                      false ->
                                          true
                                  end;
                              true ->
                                  true
                          end
                  end,
            case Res of
                {false, Errcode} ->
                    {false, Errcode};
                true ->
                    {ok, God, OldGod};
                _ ->
                    {false, ?FAIL}
            end
    end.
%% 位置是否解锁
%% 前三个位置默认解锁
pos_is_unlock(_AllGodInfo, _Unlock, Pos) when Pos =< ?DEFAULT_POS -> true;
%% 第四个位置判断套装效果
pos_is_unlock(AllGodInfo, _Unlock, Pos) when Pos =:= 4 ->
    SkillNum = god_logic:get_unlock_suit_skill_num(AllGodInfo),
    UnLockCheck = pos_is_unlock_by_suit(SkillNum, Pos),
    if
        UnLockCheck -> true;
        true -> {false, ?ERRCODE(err173_god_unlock_con_error)}
    end;

%% 第五个位置判断是否记录和套装效果
pos_is_unlock(AllGodInfo, Unlock, Pos) when Pos =:= 5 ->
    case lists:member(Pos, Unlock) of
        true ->
            SkillNum = god_logic:get_unlock_suit_skill_num(AllGodInfo),
            UnLockCheck = pos_is_unlock_by_suit(SkillNum, Pos),
            if
                UnLockCheck -> true;
                true -> {false, ?ERRCODE(err173_god_unlock_con_error)}
            end;
        false ->
            {false, ?ERRCODE(err173_god_pos_not_unlock)}
    end;
pos_is_unlock(_, _, _) -> {false, 0}.

%% 第一个助战位置默认解锁, 只需要有主战式神
secondary_pos_is_unlock(AllGodInfo, God, Pos) when ?IS_SECONDARY_GOD(Pos) andalso (Pos rem ?POS_OFFSET =:= 1) ->
    PrimaryPos = Pos div ?POS_OFFSET,
    case lists:keyfind(PrimaryPos, #god.pos, AllGodInfo) of
        #god{id = GodId} when GodId /= God#god.id -> true;
        _ -> {false, ?ERRCODE(err173_god_pos_not_unlock)}
    end;
%% 第二个助战位置需要主战式神达到3星
secondary_pos_is_unlock(AllGodInfo, God, Pos) when ?IS_SECONDARY_GOD(Pos) andalso (Pos rem ?POS_OFFSET =:= 2) ->
    PrimaryPos = Pos div ?POS_OFFSET,
    UnlockStar = data_god:get_kv(bless_pos_unlock),
    case lists:keyfind(PrimaryPos, #god.pos, AllGodInfo) of
        #god{id = GodId, star = Star} when GodId /= God#god.id andalso Star >= UnlockStar -> true;
        _ -> {false, ?ERRCODE(err173_god_pos_not_unlock)}
    end;
secondary_pos_is_unlock(_, _, _) -> {false, 0}.


%% 是否穿戴了相应套装 4号位式神至少需要1套 5号位式神至少需要2套
pos_is_unlock_by_suit(SkillNum, Pos) ->
    if
        Pos =< ?DEFAULT_POS -> true;
        ?IS_SECONDARY_GOD(Pos) andalso (Pos div ?POS_OFFSET) =< ?DEFAULT_POS -> true;
        Pos =:= 4 orelse ?IS_THE_SECONDARY_GOD(4, Pos) -> SkillNum >= 1;
        Pos =:= 5 orelse ?IS_THE_SECONDARY_GOD(5, Pos) -> SkillNum >= 2;
        true ->
            false
    end.

%% 唤神召唤检查
check_god_summon(Player, RoleGod, GodId) ->
    #role_god{god_info = GodInfo, summon_time = SummonTimeList, god_summon = GodSummon} = RoleGod,
    case GodSummon of
        undefined ->    % 第一次召唤
            #player_status{battle_attr = #battle_attr{hp = Hp}} = Player,
            case lists:keyfind(GodId, #god.id, GodInfo) of
                #god{pos = Pos} -> ok;
                _   -> Pos = 0
            end,
            case lists:keyfind(Pos, 1, SummonTimeList) of
                {_, SummonTime} -> ok;
                _ -> SummonTime = 0
            end,
            Now = utime:unixtime(),
            LastTime = Now - SummonTime,
            Cd = calc_god_cd(Player),
            IsConvoy = convoy_api:is_convoying(Player),
            if 
                Hp =< 0 ->
                    {false, ?ERRCODE(err173_without_con_to_summon)}; %% 死了不让召唤
                not ?IS_PRIMARY_GOD(Pos) -> %% 判断是否主战
                    {false, ?ERRCODE(err173_god_have_not_in_pos)};
                LastTime < Cd ->
                    {false, ?ERRCODE(err173_summon_cd)}; %% CD冷却
                IsConvoy ->
                    {false, ?ERRCODE(err500_husong_start)};
                true ->
                    FightingGods = god_logic:summon_init(GodInfo),
                    GodRet = lists:keyfind(GodId, #god_fighting.id, FightingGods),
                    if
                        FightingGods == [] orelse GodRet == false ->
                            {false, ?ERRCODE(err173_no_on_pos_god)}; %% 没有上阵式神
                        true ->
                            NewGodSummon = #god_summon{fighters = FightingGods},
                            {ok, RoleGod#role_god{god_summon = NewGodSummon}, first_summon}
                    end
            end;
        #god_summon{fighters = FightingGods} ->
            case lists:keyfind(GodId, #god.id, GodInfo) of
                God = #god{pos = Pos} -> ok;
                _   -> God = false, Pos = 0
            end,
            IsConvoy = convoy_api:is_convoying(Player),
            if
                IsConvoy ->
                    {false, ?ERRCODE(err500_husong_start)};
                not ?IS_PRIMARY_GOD(Pos) orelse God == false -> %% 判断是否主战
                    {false, ?ERRCODE(err173_no_on_pos_god)};
                true ->
                    case lists:keyfind(Pos, 1, SummonTimeList) of
                        {_, SummonTime} -> ok;
                        _ -> SummonTime = 0
                    end,
                    Now = utime:unixtime(),
                    LastTime = Now - SummonTime,
                    Cd = calc_god_cd(Player),
                    if 
                        LastTime < Cd ->
                            {false, ?ERRCODE(err173_summon_cd)};
                        true ->
                            case lists:keyfind(GodId, #god_fighting.id, FightingGods) of
                                #god_fighting{time = Time} when Time =/= 0 ->
                                    {false, ?ERRCODE(err173_god_summon)};
                                #god_fighting{} ->
                                    {ok, RoleGod, exist_summon};
                                _ ->
                                    NewFightingGods = god_logic:summon_new_fighting_god(God, FightingGods, GodInfo),
                                    {ok, RoleGod#role_god{god_summon = GodSummon#god_summon{fighters = NewFightingGods}}, new_summon}
                            end
                    end
            end
    end.

is_in_god_dun(Player) ->
    #player_status{copy_id = CopyId, dungeon = StatusDun} = Player,
    #status_dungeon{dun_id = DunId} = StatusDun,
    DunType = data_dungeon:get_dun_type(DunId),
    misc:is_process_alive(CopyId) andalso DunType == ?DUNGEON_TYPE_GOD.

calc_god_cd(Player) ->
    Cd = data_god:get_kv(god_summon_cd),
    case is_in_god_dun(Player) of
        true ->
            Decrease = data_god_dun:get_kv(cd_decrease),
            round(Decrease*Cd);
        _ ->
            Cd    
    end.

%% 抽奖检查
check_god_lottery(Player, Type, IsAotuBuy) ->
    #player_status{figure = #figure{lv = Lv}, id = RoleId} = Player,
    [Phase, BaseCounts, BaseBlessing | _] = god_lottery:ask_lottery(RoleId),
    case data_god:get_god_lottery_phase(Phase) of
        #base_god_limit_phase{god_id = GodId} ->
            AllAward0 = get_limit_lottery_award([], 0, Lv),
            AllAward = get_limit_lottery_award(AllAward0, Phase, Lv),
            case Type of
                1 ->
                    Count = 1,
                    Blessing = 1,
                    AwardList = [urand:rand_with_weight(AllAward)],
                    Cost0 = data_god:get_kv(lottery_single);
                2 ->
                    Count = 10,
                    Blessing = 10,
                    AwardList = [urand:rand_with_weight(AllAward) || _ <- lists:seq(1, Blessing)],
                    Cost0 = data_god:get_kv(lottery_ten)
            end,
            case Cost0 =/= [] andalso AllAward =/= [] andalso length(AwardList) =:= Blessing of
                true ->
                    {Award, Tv} = structure_award(AwardList, [], []),
                    [{_, CostGId, Num} | _] = Cost0,
                    [{_, OwnNum} | _] = lib_goods_api:get_goods_num(Player, [CostGId]),
                    Cost = calc_price_cost(CostGId, Num, OwnNum, IsAotuBuy),
                    %% 宠物生活技能，每日免费抽奖次数
                    FreeTimes = lib_pet_api:pet_life_skill_about_god_summon_free(Player),
                    UseTimes  = lib_daily:get_count(Player#player_status.id, ?MOD_GOD, 1),
                    %% 有免费次数则修正消耗材料
                    case UseTimes < FreeTimes of
                        true when Type =:= 1 -> Cost1 = [];
                        _ -> Cost1 = Cost
                    end,
                    if
                        Cost1 =/= false ->
                            case Cost1 == [] of
                                true when Type =:= 1 ->
                                    lib_daily:increment(RoleId, ?MOD_GOD, 1),
                                    lib_server_send:send_to_uid(RoleId, pt_173, 17321, [max(0, FreeTimes-UseTimes-1)]),
                                    {ok, Player, Phase, GodId, [], Award, Tv, Count, Blessing, BaseCounts, BaseBlessing};
                                _ ->
                                    case lib_goods_api:cost_object_list_with_check(Player, Cost, god_lottery, "") of
                                        {true, Player1, _} ->
                                            {ok, Player1, Phase, GodId, Cost, Award, Tv, Count, Blessing, BaseCounts, BaseBlessing};
                                        {false, Err, _} ->
                                            {false, Err}
                                    end
                            end;
                        true -> {false, ?ERRCODE(goods_not_enough)}
                    end;
                false -> {false, ?ERRCODE(err173_error_config)}
            end;
        _ ->
            {false, ?ERRCODE(err173_error_config)}
    end.


%% 获取奖励候选
get_limit_lottery_award(AwardList, Phase, Lv) ->
    F = fun(Id, Temp) ->
        case data_god:get_god_lottery_award(Id) of
            #base_god_limit_award{need_lv = NeedLv, weight = Weight, awards = Award, broadcast = IsTv} when Lv >= NeedLv ->
                [{Weight, {Award, IsTv}} | Temp];
            _ -> Temp
        end end,
    lists:foldl(F, AwardList, data_god:get_limit_lottery_by_phase(Phase)).

%% 构造奖励
structure_award([], Award, Tv) -> {Award, Tv};
structure_award([{[{GoodsType, GoodsId, GoodsNum}], IsTv} | T], Award, Tv) ->
    NewAward = [{GoodsType, GoodsId, GoodsNum} | Award],
    NewTv = case IsTv > 0 of
                true -> [{GoodsId, GoodsNum} | Tv];
                false -> Tv
            end,
    structure_award(T, NewAward, NewTv).

%%道具消耗逻辑
calc_price_cost(CostGId, OwnNum, OwnNum, _IsAotuBuy) ->
    [{?TYPE_GOODS, CostGId, OwnNum}];
calc_price_cost(CostGId, NeedNum, OwnNum, IsAotuBuy) ->
    case data_goods:get_goods_buy_price(CostGId) of
        {0, 0} ->
            [{?TYPE_GOODS, CostGId, NeedNum}];%%没有道具配置的话  让扣道具报道具不足
        {PriceType, Price} ->
            NeedBuy = case OwnNum >= NeedNum of
                          true ->
                              0;
                          _ ->
                              max(NeedNum - OwnNum, 1)
                      end,
            case NeedBuy =< 0 of
                true ->%%不需要购买
                    [{?TYPE_GOODS, CostGId, NeedNum}];
                false when IsAotuBuy =:= 1 ->
                    case OwnNum =< 0 of
                        true ->
                            [{PriceType, 0, Price * NeedBuy}];
                        _ ->
                            [{?TYPE_GOODS, CostGId, OwnNum}, {PriceType, 0, Price * NeedBuy}]
                    end;
                _ -> false
            end
    end.