%%%-------------------------------------------------------------------
%%% @author zmh
%%% @doc
%%%  跑马管理
%%% @end
%%%-------------------------------------------------------------------
-module(mod_glamour_mgr).

-behaviour(gen_server).
-include("glamour.hrl").
-include("predefine.hrl").
-include("scene.hrl").
-include("goods.hrl").
-include("chat.hrl").
-include("attr.hrl").
-include("figure.hrl").
-include("server.hrl").
-include("errcode.hrl").
-include("common.hrl").
-include("common_rank.hrl").
-include("role.hrl").
-include("rec_event.hrl").
-include("def_event.hrl").
-include("def_module.hrl").
%% API
-export([
    start_link/0
    ,apply_call/1
    ,apply_cast/1
    ,get_run_state/1
    ,choose_over_runer/1
    ,choose_runer/1
    ,sync_round_data/1
    ,enter_run/1
    ,enter_close_run/1
    ,use_item/4
    ,sync_runer_trust/2
    ,get_rand_heads/1
]).

%% gen_server callbacks
-export([init/1,
    handle_call/3,
    handle_cast/2,
    handle_info/2,
    terminate/2,
    code_change/3]).

-define(SERVER, ?MODULE).


apply_call(Msg) ->
    gen_server:call(?MODULE, Msg).
apply_cast(Msg) ->
    gen_server:cast(?MODULE, Msg).

get_run_state(RoleID)->
    gen_server:cast(?MODULE, {get_run_state,RoleID}).

choose_over_runer(Runers)->
   gen_server:cast(?MODULE, {choose_over_runer,Runers}).

%%同步场次
sync_round_data(Round)->
   gen_server:cast(?MODULE, {sync_round_data,Round}).

%%时间到了 不要跑了  结束
enter_close_run(Round)->
    gen_server:cast(?MODULE,{enter_close_run,Round}).

%%进入赛跑
enter_run(Scene)->
    gen_server:cast(?MODULE,{enter_run,Scene}).

%%使用气氛道具
use_item(RunID,Item,FocuserID,IsFree)->
    gen_server:cast(?MODULE,{use_item,RunID,Item,FocuserID,IsFree}).

sync_runer_trust(RunID,Trust)->
    gen_server:cast(?MODULE,{sync_runer_trust,RunID,Trust}).

get_rand_heads(RoleID)->
    gen_server:cast(?MODULE,{get_rand_heads,RoleID}).

start_link() ->
    gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).

init([]) ->
    process_flag(trap_exit, true),
    {ok,#glamour_mgr{runers=maps:new()}}.

handle_call(_Request, _From, State) ->
    {reply, ok, State}.

handle_cast(Msg, State) ->
    try
        do_handle_cast(Msg, State)
    catch
        _:Error ->
            ?ERR("handle cast exception~n"
                 "error:~p~n"
                 "state:~p~n"
                 "stack:~p", [Error, State, erlang:get_stacktrace()]),
            {noreply, State}
    end.

handle_info(Info, State) ->
    try
        do_handle_info(Info, State)
    catch
        _:Error ->
            ?ERR("handle info exception~n"
                 "error:~p~n"
                 "state:~p~n"
                 "stack:~p", [Error, State, erlang:get_stacktrace()]),
            {noreply, State}
    end.

do_handle_cast({get_run_state,RoleID},State)->
    #glamour_mgr{round=Round,runers=RunerMap}=State,
    Runers = maps:get(Round, RunerMap, []),
    Bin = pack_run_data(Round,Runers),
    lib_server_send:send_to_uid(RoleID,Bin),
    {noreply,State};

%%实时状态
do_handle_cast({get_running_state,RoleID},State)->
    #glamour_mgr{round=Round,runers=RunerMap}=State,
    Runers = maps:get(Round, RunerMap, []),
    Bin = pack_running_data(Round,Runers),
    lib_server_send:send_to_uid(RoleID,Bin),
    {noreply,State};

%%完成原始选手准备
do_handle_cast({choose_over_runer,Runers},State)->
    InitNum = data_glamour:get(init_runner),
    case length(Runers)>=InitNum of
        true->
            InitRuners = init_runer_data(Runers,[]),
            case length(InitRuners)>=InitNum of
                true->
                    Round = 1,
                    NewRuners = init_round_data(InitRuners),
                    RunerMap = maps:from_list(NewRuners),
                    NState = State#glamour_mgr{runers=RunerMap,round=Round},
                    mod_glamour_focus:init_focus_runer(NewRuners),
                    init_joiner(),
                    RoundRuners = maps:get(Round,RunerMap,[]),
                    Bin1 = pack_run_data(Round,RoundRuners),
                    lib_server_send:send_to_all(Bin1),

                    {ok,Bin} = pt_142:write(14204,[?SUCCESS]),
                    Scene = lib_guild_api:get_guild_scene(),
                    lib_server_send:send_to_all(scene,Scene,Bin);
                _->
                    mod_glamour_ctrl:enter_close(?CLOSE_NUMLESS),
                    NState = State
            end;
        _->
            mod_glamour_ctrl:enter_close(?CLOSE_NUMLESS),
            NState = State
    end,
    {noreply,NState};

%%正式进入比赛 大家跑起来
%%这里根据热门指数先后 初始化一下初始速度
do_handle_cast({enter_run,Scene},State)->
    #glamour_mgr{runers=RunerMap,round=Round}=State,
    Runers = maps:get(Round,RunerMap,[]),
    Types = data_glamour:get_types(),
    Types1 = ulists:list_shuffle(Types),
    {NewTypes,_} = ulists:split(3,Types1),
    NewRuners = init_runner_speed(Runers,NewTypes),
    Ref = erlang:send_after(1000,self(),{second_run_calc,Scene}),
    NRunerMap = maps:put(Round,NewRuners,RunerMap),
    %rand_msg(),
    %MsgRef = erlang:send_after(urand:rand(2,8)*1000,self(),rand_msg),
    {noreply,State#glamour_mgr{runers=NRunerMap,ref=Ref,click=1,swith=1}};

do_handle_cast({sync_round_data,Round},State) when Round=<3->
    #glamour_mgr{
        runers = RunerMap
    }=State,
    Runers = maps:get(Round,RunerMap,[]),
    Bin = pack_run_data(Round,Runers),
    lib_server_send:send_to_all(Bin),
    {noreply,State#glamour_mgr{round=Round}};
do_handle_cast({sync_round_data,Round},State) ->
    #glamour_mgr{
        runers = RunerMap
    }=State,
    NRuners0 = filter_round_toper(RunerMap),
    Speed = data_glamour:get(init_speed),
    NRuners = [#glamour_runer{id=Rid,figure=Figure,speed=Speed,tspeed=Speed}||#glamour_runer{id=Rid,figure=Figure}<-NRuners0],
    NRunerMap = maps:put(Round,NRuners,RunerMap),
    mod_glamour_focus:init_focus_runer(Round,NRuners),
    Bin = pack_run_data(Round,NRuners),
    lib_server_send:send_to_all(Bin),
    {noreply,State#glamour_mgr{round=Round,runers=NRunerMap}};

do_handle_cast({enter_close_run,Round},State)->
    #glamour_mgr{
        runers = RunerMap,
        click  = Click,
        swith  = IsRuning
        % msg_ref = MsgRef
    }=State,
    % util:cancel_timer(MsgRef),
    case IsRuning>=1 of
        true->
            Runers = maps:get(Round,RunerMap,[]),
            Runers0 = calc_seconds_state(Runers,Click),
            NewRuners = rank_runers(Runers0),
            Bin = pack_running_data(Round,NewRuners),
            lib_server_send:send_to_all(Bin),
            NRunerMap = maps:put(Round,NewRuners,RunerMap),
            mod_glamour_focus:enter_account(Round,NewRuners),
            NState = State#glamour_mgr{runers=NRunerMap,click=1,swith=0},
            {noreply,NState};
        _->
            {noreply,State}
    end;

%%20200828 改版 BUFF叠加使用 全程有效 无CD
do_handle_cast({use_item,RunID,Item,FocuserID,IsFree},State)->
    #glamour_mgr{
        round = Round,
        runers = RunerMap
    }=State,
    Runers = maps:get(Round,RunerMap,[]),
    Runer  = lists:keyfind(RunID,#glamour_runer.id,Runers),
    CheckList = [
        {check_runer_exit,Runer}
    ],
    case util:check_lists(lib_role_glamour,CheckList) of
        true->
            #glamour_runer{buffs=Buffs,figure=#figure{name=RName}}=Runer,
            #glamour_item{rate=Rate}=data_glamour:get_item(Item),
            case urand:rand(1,10000)=<Rate of
                true->
                    NBuffs = case lists:keyfind(Item,1,Buffs) of
                        {_,V}->
                            lists:keystore(Item,1,Buffs,{Item,V+1});
                        _->
                            [{Item,1}|Buffs]
                    end,
                    NRuner = Runer#glamour_runer{buffs=NBuffs},
                    NRuners = lists:keyreplace(RunID,#glamour_runer.id,Runers,NRuner),
                    NRunerMap = maps:put(Round,NRuners,RunerMap),
                    Res = 2,
                    Bin = pack_running_data(Round,NRuners),
                    lib_server_send:send_to_all(Bin),
                    lib_player:apply_cast(FocuserID, ?APPLY_CAST_STATUS, lib_role_glamour, auto_chat, [RName,Item]),
                    NState = State#glamour_mgr{runers=NRunerMap};
                _->
                    Res = 3,
                    NState = State

            end,
            mod_glamour_focus:back_use_item(RunID,RName,Item,FocuserID,Res,IsFree);
        {false,Err}->
            {ok,Bin} = pt_142:write(14209,[0,0,Err,0]),
            lib_server_send:send_to_uid(FocuserID,Bin),
            NState = State
    end,
    {noreply,NState};

do_handle_cast({sync_runer_trust,RunID,Trust},State)->
    #glamour_mgr{
        runers = RunerMap,
        round  = Round
    }=State,
    Runers = maps:get(Round,RunerMap,[]),
    case lists:keyfind(RunID,#glamour_runer.id,Runers) of
        Runer when is_record(Runer,glamour_runer)->
            NRuner = Runer#glamour_runer{trust=Trust},
            NRuners = lists:keyreplace(RunID,#glamour_runer.id,Runers,NRuner),
            NRunerMap = maps:put(Round,NRuners,RunerMap),
            NState = State#glamour_mgr{runers=NRunerMap},
            {noreply,NState};
        _->
            {noreply,State}
    end;

do_handle_cast({get_rand_heads,RoleID},State)->
    Joiners = case get(all_joiner) of
        Ls when is_list(Ls)->
            Ls;
        _->
            init_joiner(),
            get(all_joiner)
    end,
    {ok,Bin} = pt_142:write(14215,[Joiners]),
    lib_server_send:send_to_uid(RoleID,Bin),
    {noreply,State};


do_handle_cast(_Request, State) ->
    {noreply, State}.

%%跑马轮询
do_handle_info({second_run_calc,Scene},State)->
    #glamour_mgr{
        runers = RunerMap,
        round  = Round,
        click  = Click,
        swith  = IsRuning
    }=State,
    case IsRuning>=1 of
        true->
            Runers = maps:get(Round,RunerMap,[]),
            Runers0 = calc_seconds_state(Runers,Click),
            NewRuners = rank_runers(Runers0),
            Bin = pack_running_data(Round,NewRuners),
            lib_server_send:send_to_all(scene, Scene, Bin),
            Ref = erlang:send_after(1000,self(),{second_run_calc,Scene}),
            NRunerMap = maps:put(Round,NewRuners,RunerMap),
            NState = State#glamour_mgr{runers=NRunerMap,ref=Ref,swith=1,click=Click+1},
            {noreply,NState};
        _->
            {noreply,State}
    end;

% do_handle_info(rand_msg,State)->
%     rand_msg(),
%     MsgRef = erlang:send_after(urand:rand(2,8)*1000,self(),rand_msg),
%     {noreply,State#glamour_mgr{msg_ref=MsgRef}};

do_handle_info(_Info, State) ->
    {noreply, State}.

terminate(_Reason, _State) ->
    ok.

code_change(_OldVsn, State, _Extra) ->
    {ok, State}.


pack_run_data(Round,Runers)->
    pack_run_data(Round,Runers,[]).
pack_run_data(Round,[],Datas)->
    {ok,Bin} = pt_142:write(14201,[Round,Datas]),
    Bin;
pack_run_data(Round,[H|T],Datas)->
    #glamour_runer{
        id=RoleID,
        figure=Figure,
        speed=Speed,
        trip=Trip
    }=H,
    pack_run_data(Round,T,[{RoleID,Figure,Speed,Trip}|Datas]).


pack_running_data(Round,Runers)->
    pack_running_data(Round,Runers,[]).
pack_running_data(Round,[],Datas)->
    {ok,Bin} = pt_142:write(14211,[Round,Datas]),
    Bin;
pack_running_data(Round,[H|T],Datas)->
    #glamour_runer{
        id=RoleID,
        %speed=Speed,
        tspeed=TSpeed,
        trip=Trip,
        buffs=Buffs,
        btime=BTime
    }=H,
    pack_running_data(Round,T,[{RoleID,TSpeed,Trip,Buffs,BTime}|Datas]).

%%筛选参赛者
choose_runer(State)->
    % #common_rank_state{role_maps = RankMaps} = State,
    % RankL = maps:get(?RANK_TYPE_COMBAT, RankMaps, []),
    RankL = common_rank_logic:get_rank_list_by_rank_type(?RANK_TYPE_COMBAT),
    Ranks = split_rank(RankL,[]),
    Runers = rand_runner(Ranks),
    mod_glamour_mgr:choose_over_runer(Runers),
    {ok, State}.


split_rank([],Ranks)->
    Ranks;
split_rank([H|T],Ranks)->
    #common_rank_role{
        rank = R
    }=H,
    case R=<50 of
        true when R>0 ->
            split_rank(T,[H|Ranks]);
        _->
            split_rank(T,Ranks)
    end.

rand_runner(Ranks)->
    InitNum = data_glamour:get(init_runner),
    case length(Ranks)>= InitNum of
        true->
            urand:get_rand_list(InitNum,Ranks);
        _->
            []
    end.


%%选手数据初始化
init_runer_data([],Runers)->
    Runers;
init_runer_data([H|T],Runers)->
    #common_rank_role{role_id=RoleID}=H,
    case lib_role:get_role_show(RoleID) of
         [] ->
            init_runer_data(T,Runers);
         #ets_role_show{figure = Figure} ->
            Runer = #glamour_runer{
                id=RoleID,
                figure=Figure,
                speed=data_glamour:get(init_speed),
                tspeed=data_glamour:get(init_speed)
            },
            init_runer_data(T,[Runer|Runers])
     end.

%%初始化选手期望速度
init_runner_speed(Runers,Types)->
    NewRuners0 = lists:keysort(#glamour_runer.trust,Runers),
    Exts = data_glamour:get(trust_ext),
    NewRuners = do_init_runner_speed(NewRuners0,Exts,Types,[]),
    NewRuners.
do_init_runner_speed([],_,_,Runers)->
    Runers;
do_init_runner_speed([H|T],[],Types,Runers)->
    do_init_runner_speed(T,[],Types,[H|Runers]);
do_init_runner_speed([H|T],[V|Exts],Types,Runers)->
    case Types of
        [SType|NTypes]->
            skip;
        _->
            SType=1,NTypes=Types
    end,
    Speed = util:ceil(data_glamour:get(init_speed)*V),
    do_init_runner_speed(T,Exts,NTypes,[H#glamour_runer{stype=SType,stime=utime:unixtime(),speed=Speed,tspeed=Speed}|Runers]).

%%20200521 不在设总路程
%%跑完时间结算路程排序
calc_seconds_state(Runers,Click)->
    calc_seconds_state(Runers,Click,[]).
calc_seconds_state([],_,Runers)->
    Runers;
calc_seconds_state([H|T],Click,Runers)->
    #glamour_runer{
        stype = SType,
        speed = Speed,
        trip  = CurTrip,
        buffs = Buffs
    }=H,
    %TotalTrip = data_glamour:get(total_trip),
    Ratio = data_glamour:get_time_radio(SType,Click),
    TemS0  = util:ceil(Speed*Ratio),
    TemS  = item_effect_speed(Buffs,TemS0),
    FTrip = CurTrip+TemS,
    NewH = H#glamour_runer{
        tspeed = TemS,
        trip = FTrip
    },
    calc_seconds_state(T,Click,[NewH|Runers]).

%%排序并检测是否都已经完成
rank_runers(Runers)->
    Runers0 = compare_trip(Runers),
    NRuners = compare_rank_data(Runers0,1,[]),
    NRuners.


compare_rank_data([],_,Runers)->
    lists:reverse(Runers);
compare_rank_data([H|T],Rank,Runers)->
    compare_rank_data(T,Rank+1,[H#glamour_runer{rank=Rank}|Runers]).

%%降序
compare_trip(Runers)->
    lists:sort(fun
        (A1, A2) ->
            compare_trip(A1, A2)
    end, Runers).
compare_trip(A,B)->
    #glamour_runer{trip=TripA,tspeed=SpeedA}=A,
    #glamour_runer{trip=TripB,tspeed=SpeedB}=B,
    case TripA == TripB of
        true->
            SpeedA>=SpeedB;
        _->
            TripA>TripB
    end.

%%气氛道具速度
item_effect_speed(Buffs,TemS)->
    item_effect_speed(Buffs,TemS,1).
item_effect_speed([],TemS,Ratio)->
    util:ceil(TemS*Ratio);
item_effect_speed([{H,Num}|T],TemS,Ratio)->
    case data_glamour:get_item(H) of
        #glamour_item{type=Type}->
            Effect =  data_glamour:get_effect(Type,Num),
            case Type of
                1->
                    item_effect_speed(T,TemS,Ratio+Effect/10000);
                _->
                    item_effect_speed(T,TemS,Ratio-Effect/10000)
            end;
        _->
            item_effect_speed(T,TemS,Ratio)
    end.

%%随机摇号咸鱼
init_joiner()->
    Roles = ets:tab2list(?ETS_ROLE_SHOW),
    {NRoles,_} = ulists:split(20,Roles),
    Lists = [Figure||#ets_role_show{figure=Figure}<-NRoles],
    L = length(Lists),
    case L>= 50 of
        true->
            put(all_joiner,Lists);
        _->
            Fakes = fix_joiner(20-L,[]),
            put(all_joiner,Lists++Fakes)
    end.

fix_joiner(0,Fakes)->
    Fakes;
fix_joiner(Num,Fakes)->
    Sex = urand:rand(1,2),
    Group = data_vsn:calc_name_group(),
    FirstName = urand:list_rand(data_role_name:first_name_list(Group, Sex)),
    LastName = urand:list_rand(data_role_name:last_name_list(Group)),
    Name = LastName ++ FirstName,
    Fake = #figure{
        id = Num,
        career = Sex,
        sex = Sex,
        name = Name
    },
    fix_joiner(Num-1,[Fake|Fakes]).



% rand_msg()->
%     MsgIds  = data_glamour:get_rands(),
%     MsgSend = data_glamour:get_rand_msg(urand:list_rand(MsgIds)),
%     Name = rand_name(),
%     PackData = [19, 0, 0, "", 0, #figure{name=Name}, MsgSend, "", 0, utime:unixtime()],
%     {ok, BinData} = pt_110:write(11001, PackData),
%     lib_server_send:send_to_all(BinData).

% rand_name()->
%     LastName = urand:list_rand(data_glamour_name:last_name_list()),
%     LastName.

init_round_data(InitRuners)->
    init_round_data(InitRuners,1,[]).

init_round_data([],_,Datas)->
    Datas;
init_round_data(_,Round,Datas) when Round>=4->
    Datas;
init_round_data(InitRuners,Round,Datas)->
    {PreData,AftData} = ulists:split(3,InitRuners),
    init_round_data(AftData,Round+1,[{Round,PreData}|Datas]).


%%筛选前三轮top
filter_round_toper(RunerMap)->
    Values = maps:values(RunerMap),
    filter_round_toper(Values,[]).
filter_round_toper([],Runers)->
    Runers;
filter_round_toper([RoundAll|T],Runers)->
    case lists:keysort(#glamour_runer.rank,RoundAll) of
        [H|_]->
            filter_round_toper(T,[H|Runers]);
        _->
            filter_round_toper(T,Runers)
    end.
