%%-----------------------------------------------------------------------------
%% @Module  :       lib_fishing_util
%% @Author  :       lhy
%% @Email   :       liuhouying73@qq.com
%% @Created :       2018-09-28
%% @Description:    钓鱼系统
%%-----------------------------------------------------------------------------
-module(lib_fishing_util).
-include("fishing.hrl").
-include("figure.hrl").
-include("server.hrl").
-include("common.hrl").
-include("errcode.hrl").
-include("goods.hrl").
-include("def_goods.hrl").
-include("def_daily.hrl").
-include("def_module.hrl").
-include("def_fun.hrl").
-include("vip.hrl").
-include("live_skill.hrl").
-include("def_act_label.hrl").

-export([
         %% ------------------------ 其它 ----------------------------------------------------------
          initialize_fish_basket/1                 %% 初始化鱼筐
         ,auto_change_fishing_gear/2               %% 自动切换渔具
         ,cache/7                                  %% 缓存已上钩的鱼类ID

         %% ------------------------ 获取 -------------------------------------------------------
         ,return_usage_count/2                     %% 获取单个鱼竿使用次数
         ,get_usage_count/2                        %% 获取鱼竿使用次数判断鱼竿消耗
         ,get_hooked_fish/1                        %% 获取上钩的鱼类ID
         ,get_fish_balance/1                       %% 获取鱼类的平衡值范围
         ,get_log_cache/1                          %% 获取日志缓存数据
         ,get_fish_type/1                          %% 获取鱼类品质
         ,get_weight_list/2                        %% 获取权重表
         ,get_probability/1                        %% 获取渔具的权重加成
         ,get_fishing_gear_selected/1              %% 获取选择的渔具
         ,get_fishing_lv_prob/1                    %% 获取钓鱼等级不消耗活力值和鱼竿使用次数的概率
         ,get_fishing_gear_quality_type/1          %% 获取鱼竿的品质类型
         ,select_water_area/2                      %% 获取水域

         %% ------------------------ 更新 --------------------------------------------------------
         ,update_fish_basket/2                     %% 更新鱼筐记录
         ,update_fish_rod_usage_count/4            %% 更新鱼竿的使用次数
         ,update_unlock_lv_unlock/2                %% 更新钓鱼信息
         ,update_lv/2                              %% 更新钓鱼等级
         ,update_fishing_act/3                     %% 更新钓鱼状态标记
         ,update_selected_fishing_gear/3           %% 更新渔具选择

         ,sync_fish_rod/1                          %% 同步鱼竿
]).

%% 初始化鱼筐记录
initialize_fish_basket(PS) ->
    Fishing = PS#player_status.fishing,
    NewFishing = Fishing#fishing{fish_basket = []},
    NewPS = PS#player_status{fishing = NewFishing},
    NewPS.

%% 自动切换渔具
auto_change_fishing_gear(PS, Type) ->
    #player_status{id = RoleId, figure = #figure{lv = Lv}} = PS,
    RoleId = PS#player_status.id,
    GoodsStatus = lib_goods_do:get_goods_status(),
    #goods_status{dict = Dict} = GoodsStatus,
    GoodsList = lib_goods_util:get_goods_list(RoleId, ?GOODS_LOC_BAG, Dict, Lv),
    FishingGearList = case GoodsList == [] of
                        true -> [];
                        false -> [Goods#goods.goods_id || Goods <- GoodsList
                                 , (Goods#goods.type == ?GOODS_TYPE_FISHING andalso Goods#goods.subtype == ?GOODS_SUBTYPE_FISHING_GEAR)]
                      end,
    case do_auto_change_fishing_rod(FishingGearList, Type) of
      0 ->
        {false};
      Selected ->
        NewPS = update_selected_fishing_gear(PS, Selected, Type),
        {true, NewPS}
   end.

%% 更换渔具
update_selected_fishing_gear(PS, Selected, Type) ->
   Fishing = PS#player_status.fishing,
   [FishingRodId, BaitId] = get_fishing_gear_selected(Fishing),
   case Type of
     1 ->
       NewFishingRodId = Selected,
       NewBaitId = BaitId;
     2 ->
       NewFishingRodId = FishingRodId,
       NewBaitId = Selected
   end,
   NewFishingGearSelect = #fishing_gear_select{fishing_rod_id = NewFishingRodId, bait_id = NewBaitId, hooked_fish_id = 0},
   NewFishing = Fishing#fishing{fishing_gear_select = NewFishingGearSelect},
   NewPS = PS#player_status{fishing = NewFishing},
   NewPS.

%% 自动切换鱼竿
do_auto_change_fishing_rod([], _) -> 0;
do_auto_change_fishing_rod([FishingGearId | FishingGearList], Type) ->
    case data_fishing:get_fishing_gear_property(FishingGearId) of
      [] ->
        0;
      #base_fishing_gear{fishing_gear_type = FishingGearType} ->
        if
          FishingGearType == Type ->
            FishingGearId;
          true ->
            do_auto_change_fishing_rod(FishingGearList, Type)
        end
    end.

%% 缓存已上钩的鱼类ID
cache(FishId, SceneId, SelectedArea, MaunalOrAuto, CacheRodsCost, CostEnergyValue, PS) ->
    Fishing = PS#player_status.fishing,
    FishingGearSelect = Fishing#fishing.fishing_gear_select,
%    LogCache = Fishing#fishing.log_cache,
    NewFishingGearSelect = case FishingGearSelect of
                             [] ->
                               #fishing_gear_select{hooked_fish_id = FishId};
                             _ ->
                               FishingGearSelect#fishing_gear_select{hooked_fish_id = FishId}
    end,
    LogCache = #log_cache{scene_id = SceneId, water_area = SelectedArea, maunal_or_auto = MaunalOrAuto,
                          rods_usage_cost = CacheRodsCost, energy_cost = CostEnergyValue},
    NewFishing = Fishing#fishing{fishing_gear_select = NewFishingGearSelect, log_cache = LogCache},
    NewStatus = PS#player_status{fishing = NewFishing},
    {ok, NewStatus}.

%% 返回使用中鱼竿的使用次数
return_usage_count(PS, FishingRodId) ->
    UsageCountSum = get_usage_count_sum(PS,FishingRodId),
    BaseFishRod = data_fishing:get_fishing_gear_property(FishingRodId),
    SingleCount = BaseFishRod#base_fishing_gear.usage_count,
    Rem = UsageCountSum rem SingleCount,
    if
      Rem == 0 andalso UsageCountSum > 0 ->
        UsageCount = SingleCount;
      true ->
        UsageCount = Rem
    end,
    UsageCount.

%% 判断使用中鱼竿的使用次数
get_usage_count(PS, FishingRodId) ->
    UsageCountSum = get_usage_count_sum(PS, FishingRodId),
    BaseFishRod = data_fishing:get_fishing_gear_property(FishingRodId),
    SingleCount = BaseFishRod#base_fishing_gear.usage_count,
    UsageCount = UsageCountSum rem SingleCount,
    UsageCount.

%% 获取鱼竿总使用次数
get_usage_count_sum(PS, FishingRodId) ->
    #player_status{fishing = Fishing} = PS,
    #fishing{fish_rod_usage_count = FRUC} = Fishing,
    case lists:keyfind(FishingRodId, 1, FRUC) of
      false ->
        0;
      {_, UsageCountSum} ->
        UsageCountSum
    end.

%% 获取已上钩的鱼类
get_hooked_fish(PS) ->
    #player_status{fishing = Fishing} = PS,
    #fishing{fishing_gear_select = FishingGearSelect} = Fishing,
    case FishingGearSelect of
      [] ->
        FishId = 0,
        NewPS = PS;
      _ ->
        FishId = FishingGearSelect#fishing_gear_select.hooked_fish_id,
        NewFishingGearSelect = FishingGearSelect#fishing_gear_select{hooked_fish_id = 0},
        NewFishing = Fishing#fishing{fishing_gear_select = NewFishingGearSelect},
        NewPS = PS#player_status{fishing = NewFishing}
    end,
    {FishId, NewPS}.

%% 获取鱼类的平衡值范围
get_fish_balance(FishId) ->
    case FishId of
      0 ->
        0;
      _ ->
        BaseFish = data_fishing:get_fish_property(FishId),
        RangeOfBalance = BaseFish#base_fish.range_of_balance,
        RangeOfBalance
    end.

%% 获取日志缓存数据
get_log_cache(Fishing) ->
    LogCache = Fishing#fishing.log_cache,
    case LogCache of
      [] ->
        {0, 0, 0};
      _ ->
        #log_cache{scene_id = SceneId, water_area = WaterArea, maunal_or_auto = MaunalOrAuto,
                   rods_usage_cost = CacheRodsCost, energy_cost = CostEnergyValue} = LogCache,
        {SceneId, WaterArea, MaunalOrAuto, CacheRodsCost, CostEnergyValue}
    end.

%% 获取鱼类品质
get_fish_type(FishId) ->
    BaseFish = data_fishing:get_fish_property(FishId),
    case BaseFish of
      [] ->
        0;
      _ ->
        FishType = BaseFish#base_fish.quality_type,
        FishType
    end.

%% 获得权重表
get_weight_list(FishList, ProbList) ->
    F = fun(FishId, WeightList) ->
      case data_fishing:get_fish_property(FishId) of
        [] ->
          WeightList;
        BaseFish ->
          #base_fish{hook_probability = FishHookProb, quality_type = Type} = BaseFish,
          case lists:keyfind(Type, 1, ProbList) of
            false ->
              Weight = FishHookProb;
            {_, Prob} ->
              Weight = Prob + FishHookProb
          end,
          [{Weight, FishId} | WeightList]
      end
    end,
    lists:foldl(F, [], FishList).

%% 获得被选择的渔具
get_fishing_gear_selected(Fishing) ->
    FishingGearSelect = Fishing#fishing.fishing_gear_select,
    case FishingGearSelect of
      [] ->
        [0, 0];
      _ ->
        FishingRodId = FishingGearSelect#fishing_gear_select.fishing_rod_id,
        BaitId = FishingGearSelect#fishing_gear_select.bait_id,
        case FishingRodId =/= 0 andalso BaitId =/= 0 of
         true ->
            [FishingRodId, BaitId];
         false ->
            [0,0]
        end
    end.

%% 获取渔具的权重加成
get_probability(Fishing) ->
    #fishing{fishing_gear_select = FishingGearSelect, lv = FishLv} = Fishing,
    case data_fishing:get_fishing_lv_property(FishLv) of
      #base_fishing_lv{fish_quality_pro = QualityProUp} -> skip;
      QualityProUp -> skip
    end,
    #fishing_gear_select{fishing_rod_id = FishingRodId, bait_id = BaitId} = FishingGearSelect,
    BaseFishingRodMsg = data_fishing:get_fishing_gear_property(FishingRodId),
    BaseBaitMsg = data_fishing:get_fishing_gear_property(BaitId),
    RodProbList = BaseFishingRodMsg#base_fishing_gear.probability,
    BaitProbList = BaseBaitMsg#base_fishing_gear.probability,
    F = fun(T, ProbList) ->
      {Type, Prob} = T,
      case lists:keyfind(Type, 1, ProbList) of
        false ->
          NewProb = Prob;
        {_, OldProb} ->
          NewProb = OldProb + Prob
      end,
      lists:keystore(Type, 1, ProbList, {Type, NewProb})
    end,
    NewProbList = lists:foldl(F, RodProbList, BaitProbList ++ QualityProUp),
    NewProbList.

%% 获取钓鱼等级不消耗活力值和鱼竿使用次数的概率
get_fishing_lv_prob(Lv) ->
    BaseFishingLv = data_fishing:get_fishing_lv_property(Lv),
    case BaseFishingLv of
      [] ->
        [0, 0];
      _ ->
        NoComsumeRodPro = BaseFishingLv#base_fishing_lv.no_comsume_rod_pro,
        NoComsumeEnergyPro = BaseFishingLv#base_fishing_lv.no_comsume_energy_pro,
       RodWeightList = [{NoComsumeRodPro, 1},{?RATIO - NoComsumeRodPro, 0}],
       EnergyWeightList = [{NoComsumeEnergyPro, 1},{?RATIO- NoComsumeEnergyPro, 0}],
       case urand:rand_with_weight(RodWeightList) of
          false ->
             NoComsumeRodFlag = 0;
          NoComsumeRodFlag ->
             skip
       end,
       case urand:rand_with_weight(EnergyWeightList) of
          false ->
             NoComsumeEnergyFlag = 0;
          NoComsumeEnergyFlag ->
             skip
       end,
       [NoComsumeEnergyFlag, NoComsumeRodFlag]
   end.

%% 获取鱼竿的品质类型
get_fishing_gear_quality_type(FishingGearId) ->
    case data_fishing:get_fishing_gear_property(FishingGearId) of
      #base_fishing_gear{quality_type = QualityType} ->
        QualityType;
      _ ->
        0
    end.

%% 获取钓鱼水域
select_water_area(WaterArea, MaunalOrAuto) ->
    FarFlag = WaterArea band 4,
    MiddleFlag = WaterArea band 2,
    NearFlag = WaterArea band 1,
    case MaunalOrAuto of
     1 ->
       SelectedArea = maunal_select(WaterArea);
     2 ->
       WaterList = [Falg || Falg <- [FarFlag, MiddleFlag, NearFlag], Falg =/= 0],
       [T|_] = ulists:list_shuffle(WaterList),
       SelectedArea = maunal_select(T);
     _ ->
       SelectedArea = 0
   end,
   SelectedArea.

maunal_select(WaterArea) ->
   case WaterArea of
     4 ->
       ?FAR;
     _ ->
       WaterArea
   end.

%% 更新鱼筐记录
update_fish_basket(PS, FishId) ->
    #player_status{fishing = Fishing} = PS,
    #fishing{fish_basket = FishBasket} = Fishing,
    case lists:keyfind(FishId, 1, FishBasket) of
      false ->
        NewBasket = lists:keystore(FishId, 1, FishBasket, {FishId, 1});
      {_Id, Num} ->
        NewBasket = lists:keystore(FishId, 1, FishBasket, {FishId, Num + 1})
    end,
    NewFishing = Fishing#fishing{fish_basket = NewBasket},
    NewPS = PS#player_status{fishing = NewFishing},
    {ok, NewPS}.

%% 更新鱼竿总次数
update_fish_rod_usage_count(PS, FishingRodId, Num, Flag) ->
    #player_status{fishing = Fishing} = PS,
    #fishing{fish_rod_usage_count = FRUC} = Fishing,
    case lists:keyfind(FishingRodId, 1, FRUC) of
      false ->
        OldNum = 0;
      {_, OldNum} ->
        skip
    end,
    NewFRUC = case Flag of
      ?PLUS ->
        lists:keystore(FishingRodId, 1, FRUC, {FishingRodId, OldNum + Num});
      ?MINUS ->
        if
          OldNum == 0 ->
            FRUC;
          true ->
            lists:keystore(FishingRodId, 1, FRUC, {FishingRodId, OldNum - Num})
        end
    end,
    NewFishing = Fishing#fishing{fish_rod_usage_count = NewFRUC},
    NewPS = PS#player_status{fishing = NewFishing},
    {ok,NewPS}.

%% 更新钓鱼信息
update_unlock_lv_unlock(Status, _FishId) ->
   Fishing = Status#player_status.fishing,
   [FishingRodId, _] = get_fishing_gear_selected(Fishing),
   case FishingRodId of
     0 ->
       {ok, Status};
     _ ->
        BaseFishingGear = data_fishing:get_fishing_gear_property(FishingRodId),
        IncrMastery = BaseFishingGear#base_fishing_gear.incr_mastery,
        #fishing{mastery = Mastery, lv = Lv} = Fishing,
        {NewLv, NewMastery} = update_lv(Lv, Mastery + IncrMastery),
        NewFishing = Fishing#fishing{lv = NewLv, mastery = NewMastery},
        NewStatus = Status#player_status{fishing = NewFishing},
        LastPS = lib_live_skill:notify_skill_change(NewStatus, ?TYPE_FISH_SKILL, NewLv, NewMastery),
        {ok, LastPS}
   end.

%% 更新钓鱼等级
update_lv(Lv, Mastery) ->
  BaseFishingLv = data_fishing:get_fishing_lv_property(Lv),
  MasteryMax = BaseFishingLv#base_fishing_lv.mastery,
  if
    MasteryMax == 0 ->  %% 已满级
      {Lv, 0};
    Mastery < MasteryMax ->
      {Lv, Mastery};
    true ->
      case data_fishing:get_fishing_lv_property(Lv + 1) of
        #base_fishing_lv{} ->
          update_lv(Lv + 1, Mastery - MasteryMax);
        _ ->
          {Lv, MasteryMax}
      end
  end.

%% 更新钓鱼状态标记
update_fishing_act(Args, Type, Flag) ->
  [RoleId, SceneId, PoolId, CopyId, X, Y] = Args,
  lib_player:update_player_info(RoleId, [{act_label, [{Type, Flag}]}]),
  mod_scene_agent:update(SceneId, PoolId, RoleId, [{act_label, [{Type, Flag}]}]),
  lib_scene:broadcast_player_act_label(RoleId, SceneId, PoolId, CopyId, X, Y, [{Type, Flag}]).

%% 同步鱼竿使用次数
sync_fish_rod(PS) ->
    #player_status{id = RoleId, fishing = Fishing, figure = #figure{lv = Lv}} = PS,
    #fishing{fish_rod_usage_count = FishRodUsageCount} = Fishing,
    GoodsStatus = lib_goods_do:get_goods_status(),
    #goods_status{dict = Dict} = GoodsStatus,
    GoodsList = lib_goods_util:get_goods_list(RoleId, ?GOODS_LOC_BAG, Dict, Lv),
    FishingGearList = case GoodsList == [] of
                        true -> [];
                        false -> [{Goods#goods.goods_id, Goods#goods.num} || Goods <- GoodsList
                                 , (Goods#goods.type == ?GOODS_TYPE_FISHING andalso Goods#goods.subtype == ?GOODS_SUBTYPE_FISHING_GEAR)]
                      end,
    case FishingGearList of
      [] ->
        {ok, PS};
      _ ->
        NewBagFishRod = sync_bag_fish_rod(FishingGearList, FishRodUsageCount),
        NewFishing = Fishing#fishing{fish_rod_usage_count = NewBagFishRod},
        NewPS = PS#player_status{fishing = NewFishing},
        lib_fishing:db_player_fishing_replace(NewPS),
        {ok, NewPS}
    end.

sync_bag_fish_rod(FishingGearList, BagFishRod) ->
    F = fun(T, Acc) ->
      {Id, Num} = T,
      case data_fishing:get_fishing_gear_property(Id) of
      [] ->
        Acc;
      BaseFishGear ->
        case BaseFishGear#base_fishing_gear.fishing_gear_type of
          ?RODTYPE ->
            UsageCount = BaseFishGear#base_fishing_gear.usage_count,
            case lists:keyfind(Id, 1, BagFishRod) of
              false ->
                UsageCountSum = UsageCount * Num;
              {_, UsageCountSum} ->
                skip
            end,
            case lists:keyfind(Id, 1, Acc) of
              false ->
                if
                  UsageCountSum =< 0 ->
                    Rem = UsageCountSum rem UsageCount,
                    [{Id, Num * UsageCount + Rem} | Acc];
                  (UsageCountSum rem UsageCount == 0) andalso (UsageCountSum div UsageCount == Num) ->
                    [{Id, UsageCountSum} | Acc];
                  (UsageCountSum rem UsageCount =/= 0) andalso (UsageCountSum div UsageCount == Num - 1) ->
                    [{Id, UsageCountSum} | Acc];
                  UsageCountSum rem UsageCount =/= 0 ->
                    Rem = UsageCountSum rem UsageCount,
                    [{Id, (Num - 1) * UsageCount + Rem} | Acc];
                  true ->
                    [{Id, Num * UsageCount} | Acc]
                end;
              {_, OldNum} ->
                lists:keystore(Id, 1, Acc, {Id, UsageCount * Num + OldNum})
            end;
          _ ->
            Acc
        end
      end
    end,
    lists:foldl(F, [], FishingGearList).
