%%%-------------------------------------------------------------------
%%% @author liushl
%%% @doc
%%%     羁绊对外接口
%%% @end
%%%-------------------------------------------------------------------
-module(mate_api).
-author("liushl").

-include("server.hrl").
-include("mate.hrl").
-include("predefine.hrl").
-include("def_module.hrl").
-include("figure.hrl").
-include("rec_event.hrl").
-include("def_event.hrl").
-include("scene.hrl").
-include("rec_offline.hrl").
-include("relationship.hrl").
%% API
-export([
    login/1,                        %% 登陆初始化
    calc_power/3,                   %% 全局统计战力时，加上额外技能战力
    is_mate/2,                      %% 是否羁绊关系
    get_role_mate_title/1,          %% 获得玩家每个羁绊的称号
    role_get_mate_title/1,          %% 获得玩家每个羁绊的称号
    role_get_wear_mate/1,           %% 获得玩家佩戴的羁绊称号
    get_wear_mate_role/1,           %% 获得玩家佩戴的羁绊玩家
    get_mate_goods/1,               %% 获得玩家羁绊信物
    get_all_mate_role/1,
    handle_event/2,
    when_my_mate_change_name/3,     %% 我的羁绊好友改名字了
    when_upgrade_intimacy_lv/3,     %% 亲密度提升了
    get_mate_attr/1,                %% 获得羁绊系统属性
    loading_ets_data/0,             %% 加载玩家离线时间
    logout/1,                       %% 更新玩家离线时间
    
    update_mate_power/1             %% 更新属性
]).

%% 登陆初始化
login(RoleId) when is_integer(RoleId) ->
    MateList = db:get_all(?SQL_MATE_GET_ALL_MATE, [RoleId]),
    FormatMates = [
        #mate_info{
            id = Other
            , remarks = Remarks
            , title = Title
            , time = Time
            , anniversary = util:bitstring_to_term(AnniversaryBin)
        }
        ||[Other, Remarks, Title, Time, AnniversaryBin] <- MateList
    ],
    case db:get_row(?SQL_MATE_GET_MATE_ROLE_INFO, [RoleId]) of
        [BoatStage, BoatStar, BoatExp, WearMate, Newbee] ->
            #role_mate{mate_list = FormatMates
                , boat_stage = BoatStage
                , boat_star = BoatStar
                , boat_exp = BoatExp
                , wear_mate = WearMate
                , newbee = Newbee
            };
        _ ->
            #role_mate{mate_list = FormatMates}
    end;
login(Player) ->
    #player_status{
        id = RoleId,
        figure = #figure{lv = Lv},
        mate = RoleMate
    } = Player,
    NewMate = include_mate_attr(RoleId, Lv, RoleMate),
    TaskList = db:get_all(?SQL_MATE_SELECT_DAILY_TASK_INFO, [RoleId]),
    RelaInfo =
    [
        {OtherId, TaskId, Progress, State} ||[OtherId, TaskId, Progress, State] <- TaskList
    ],
    MateDaily =
    case db:get_row(?SQL_MATE_GET_DAILY_INFO, [RoleId]) of
        [Time, Stranger] ->
            #mate_daily{
                time = Time
                , rela_info = RelaInfo
                , stranger_info = util:bitstring_to_term(Stranger)
            };
        _ ->
            #mate_daily{}
    end,
    Player#player_status{mate = NewMate#role_mate{mate_daily = MateDaily}}.

%% 全局统计战力时，加上额外技能战力
calc_power(Player, _AttrPower, _BaseAttr) ->
    RoleMate = Player#player_status.mate,
    case RoleMate of
        #role_mate{extra_power = ExtraPower, attr = _Attr} ->
            %PartialAttr = attr_conv:to_attr_record(Attr),
            %Power = lib_player_attr:calc_attr_power_partial(AttrPower, BaseAttr, PartialAttr) + ExtraPower,
            {Player, ExtraPower};
        _ ->
            {Player, 0}
    end.

%% 是否羁绊关系
is_mate(Player, TargetRRole) ->
    lists:keymember(TargetRRole, #mate_info.id, Player#player_status.mate#role_mate.mate_list).

%% 获得玩家每个羁绊的称号
get_role_mate_title(RoleId) ->
    List = db:get_all(?SQL_MATE_GET_MATE_TITLE, [RoleId]),
    [
        {Other, Title} || [Other, Title] <- List
    ].

%% 获得玩家每个羁绊的称号
role_get_mate_title(Player) ->
    [
        {Other, Title} || #mate_info{id = Other, title = Title} <- Player#player_status.mate#role_mate.mate_list
    ].

%% 获得玩家佩戴的羁绊称号
role_get_wear_mate(Player) ->
    MateRole = Player#player_status.mate#role_mate.wear_mate,
    case MateRole =:= 0 of
        true  -> {"", "", 0};
        false ->
            case lists:keyfind(MateRole, #mate_info.id, Player#player_status.mate#role_mate.mate_list) of
                #mate_info{title = Title} ->
                    {lib_role:get_role_name(MateRole), Title, role_get_wear_mate_lv(Player#player_status.id, MateRole)};
                false ->
                    {"", "", 0}
            end
    end.

%% 获得玩家佩戴的羁绊称号等级
role_get_wear_mate_lv(RoleId, MateRole) ->
    [{_, _Rela, Intimacy}] = lib_relationship_api:get_rela_and_intimacy_online(RoleId, [MateRole]),
    IntimacyLv = data_relationship:get_intimacy_lv(Intimacy),
    IntimacyLv.

%% 获得玩家佩戴的羁绊玩家
get_wear_mate_role(Player) ->
    case Player#player_status.mate of
        #role_mate{wear_mate = WearMate} -> WearMate;
        _ -> 0
    end.

%% 获得玩家羁绊信物
get_mate_goods(Player) ->
    case Player#player_status.mate of
        #role_mate{boat_stage = Stage, boat_star = Star} ->
            {Stage, Star};
        _ -> {0, 0}
    end.

%% 改名
handle_event(Player, #event_callback{type_id = ?EVENT_RENAME, data = NewName}) when is_record(Player, player_status) ->
    #player_status{mate = #role_mate{mate_list = MateList}, id = RoleId} = Player,
    [
        lib_player:apply_cast(MateRole, ?APPLY_CAST_STATUS, ?MODULE, when_my_mate_change_name, [RoleId, NewName])
        ||#mate_info{id = MateRole} <- MateList
    ],
    {ok, Player};
%% 客户端登陆完成
handle_event(Player, #event_callback{type_id = ?EVENT_CLIENT_LOGIN_SUCCESS}) when is_record(Player, player_status) ->
    mate_mgr:login(Player#player_status.id),
    {ok, Player};
handle_event(Player, #event_callback{type_id = ?EVENT_DISCONNECT}) ->
    mate_mgr:logout(Player#player_status.id),
    {ok, Player};
handle_event(Player, _) ->
    {ok, Player}.

%% 我的羁绊好友改名字了
when_my_mate_change_name(Player, MateRole, MateName) ->
    #player_status{mate = #role_mate{wear_mate = WearMate}} = Player,
    case WearMate =:= MateRole of
        true  ->
            mod_scene_agent:update(Player, [{mate_name, MateName}]),
            lib_scene:broadcast_player_scene_info(Player, [{?SCENE_USER_UPDATE_MATE_ROLE, MateName}]);
        false ->
            ok
    end,
    Player.

%% 亲密度提升了
when_upgrade_intimacy_lv(Player, NewLv, Other) ->
    case is_mate(Player, Other) of
        true  ->
            case get_wear_mate_role(Player) =:= Other of
                true  ->
                    mod_scene_agent:update(Player, [{mate_lv, NewLv}]),
                    lib_scene:broadcast_player_scene_info(Player, [{?SCENE_USER_UPDATE_MATE_LV, NewLv}]);
                false ->
                    ok
            end,
            update_mate_power(Player);
        false ->
            Player
    end.

%% 获得羁绊系统属性
get_mate_attr(Player) ->
    case Player#player_status.mate of
        #role_mate{attr = Attr} -> Attr;
        _ -> []
    end.

%% 获得羁绊信息。亲密度排序
get_all_mate_role(Player) ->
    #player_status{
        id = RoleId,
        mate = RoleMate,
        off = StatusOff
    } = Player,
    case RoleMate of
        #role_mate{mate_list = [_|_] = MateList} ->
            MateRoleIds = [Id || #mate_info{id = Id} <- MateList],
            MateRoleIntimacy =
                case StatusOff#status_off.relationship of
                    Relas when is_list(Relas) ->
                        %% 离线玩家
                        [
                            case lists:keyfind(TmpRoleId, #rela.other_rid, Relas) of
                                false -> {TmpRoleId, 0};
                                #rela{intimacy = Intimacy} -> {TmpRoleId, Intimacy}
                            end || TmpRoleId <- MateRoleIds
                        ];
                    _ ->
                        [
                            {TmpRoleId, Intimacy}
                            ||{TmpRoleId, _, Intimacy} <- lib_relationship_api:get_rela_and_intimacy_online(RoleId, MateRoleIds)
                        ]
                end,
            F = fun({_, A}, {_, B}) -> A > B end,
            lists:sort(F, MateRoleIntimacy);
        _ ->
            []
    end.

loading_ets_data() ->
    case db:get_all(io_lib:format(?SQL_SELECT_ROLE_IDS, [])) of
        [_|_] = List ->
            EtsName = ?ETS_ROLE_LOGOUT_TIME,
            [ets:insert(EtsName, {RoleId, LogoutTime}) || [RoleId, LogoutTime] <- List];
        _ ->
            ok
    end,
    ok.

logout(Player) ->
    ets:insert(?ETS_ROLE_LOGOUT_TIME, {Player#player_status.id, utime:unixtime()}).

%%---------------------------------------------------------------------
%% @doc 更新属性，战力计算在回调 lib_player_attr:update_module_power/3 里通过调用mate_api:calc_power/3计算
%%---------------------------------------------------------------------
update_mate_power(Player) ->
    NewMate = include_mate_attr(Player#player_status.id, Player#player_status.figure#figure.lv, Player#player_status.mate),
    Player1 = Player#player_status{mate = NewMate},
    Player2 = lib_player:count_player_attribute(Player1),
    lib_player:send_attribute_change_notify(Player2, ?NOTIFY_ATTR),
    mod_scene_agent:update(Player2, [{battle_attr, Player2#player_status.battle_attr}]),
    Player2.

%%---------------------------------------------------------------------
%% @doc 统计羁绊系统属性
%% 每个伙伴的亲密度属性
%% 小船属性
include_mate_attr(RoleId, Lv, RoleMate) ->
    #role_mate{mate_list = MateList} = RoleMate,
    %% 亲密
    IntimacyAttr = lists:foldl(
        fun(#mate_info{id = Other}, Temp) ->
            IntimacyLv = role_get_wear_mate_lv(RoleId, Other),
            OneIntimacy = data_mate:get_mate_lv_attr(IntimacyLv),
            OneIntimacy ++ Temp
        end, [], MateList
    ),
    
    %% 小船
    {BoatAttr, BoatSkills} = include_boat_attr(Lv, RoleMate),
    %% 技能属性
    SkillAttr = lib_skill_attr:count_skill_attr_with_mod_id(?MOD_EQUIP, BoatSkills, Lv),
    %% 技能虚战力
    ExtraPower = lib_skill:count_skill_power(BoatSkills),
    FinalAttr = util:combine_list(BoatAttr ++ IntimacyAttr ++ SkillAttr),
    RoleMate#role_mate{attr = FinalAttr, extra_power = ExtraPower}.
include_boat_attr(Lv, RoleMate) ->
    case lib_module:get_open_lv(?MOD_MATE) =< Lv of
        true  ->
            case data_mate:get_mate_boat(RoleMate#role_mate.boat_stage, RoleMate#role_mate.boat_star) of
                #base_mate_boat{attr = BoatAttr} ->
                    BoatAttr;
                _ ->
                    BoatAttr = []
            end,
            BoatSkills = include_mate_boat_skill(RoleMate#role_mate.boat_stage, data_mate:get_mate_boat_all_skills(), []),
            {BoatAttr, BoatSkills};
        false ->
            {[], []}
    end.
include_mate_boat_skill(BoatStage, [{NeedStage, SkillId}|T], Skills) when BoatStage >= NeedStage ->
    include_mate_boat_skill(BoatStage, T, [{SkillId, 1}|Skills]);
include_mate_boat_skill(_, _, Skills) -> Skills.
