%%%-------------------------------------------------------------------
%%% @author zmh
%%% @doc
%%%
%%% @end
%%%-------------------------------------------------------------------
-module(lib_role_uranium).
-include("server.hrl").
-include("common.hrl").
-include("scene.hrl").
-include("errcode.hrl").
-include("def_module.hrl").
-include("predefine.hrl").
-include("role_uranium.hrl").
-include("figure.hrl").
-include("def_goods.hrl").
-include("skill.hrl").
-include("def_event.hrl").
-include("rec_event.hrl").

-compile(export_all).
%% API
-export([
	login/1,
	uranium_lv/2,
	check/1,
    get_attr/1,
    calc_power/3
]).
-define(MATERIAL_USE, material_use).  %data_uranium.erl改变这里也要改变
-define(MaxAutoNum, 10).
%%登录加载
login(Status)->
    #player_status{
        id=RoleID,
        skill=StatusSkill,
        figure=#figure{lv=RoleLv}
    }=Status,
	Sql = io_lib:format(?SQL_ROLE_URANIUM_GET, [RoleID]),
    RoleUranium = case db:get_row(Sql) of
        % [Grade,Lv,ITime,HTime,QTime] ->
        [Grade, Lv, HaveEnergy] ->
            #role_uranium{
	            grade = Grade,
		        lv = Lv,
                have_energy = HaveEnergy
		        % init_time = ITime,
		        % start_time = HTime,
                % quick_time = QTime
            };
        _ ->
            InitData = init_data(),
            save_role_uranium(RoleID,InitData),
            InitData
    end,
    #role_uranium{grade=UGrade}=RoleUranium,
    #status_skill{skill_list=SkillList}=StatusSkill,
    #base_uranium_grade{skills=USkills}=data_uranium:get_uranium_grade(UGrade),
    NSkillList = update_skills(SkillList,USkills),
    {SkillAttr, SkillPower} = lib_skill_attr:get_passive_skill_attr_and_power(NSkillList, RoleLv),
    HpResumeSpclAdd = lib_skill:count_hp_resume_spcl_add(RoleLv, NSkillList),
    NStatusSkill = StatusSkill#status_skill{
        skill_list = NSkillList
        ,hp_resume_spcl_add = HpResumeSpclAdd
        ,skill_power = SkillPower,skill_attr = SkillAttr
    },
    Status#player_status{role_uranium=RoleUranium,skill=NStatusSkill}.

handle_event(Player, #event_callback{type_id = ?EVENT_CLIENT_LOGIN_SUCCESS}) ->
	#player_status{role_uranium = RoleUranium} = Player,
	#role_uranium{grade = Grade} = RoleUranium,
	case data_uranium:get_uranium_grade(Grade) of
		#base_uranium_grade{skills = Skills} -> ok;
		_ -> Skills = []
	end,
	case Skills of
		[_|_] = SkillValue -> ok;
		_ -> SkillValue = []
	end,
	SkillValue =/= [] andalso lib_achievement_api:uranium_skill_event(Player, SkillValue),
	{ok, Player};
handle_event(Player, _) ->
	{ok, Player}.

%%数据初始化
init_data()->
    #role_uranium{have_energy = 0}.
	% Now = utime:unixtime(),
	% #role_uranium{
	% 	init_time = Now,
	% 	start_time = Now
	% }.




cal_maxcost_energy(E, HaveEnergy, _Grade, []) -> E - HaveEnergy;
cal_maxcost_energy(E, HaveEnergy, Grade, [Lv|ListLv]) ->
    #base_uranium_lv{energy = LevelNeedEnergy} = data_uranium:get_uranium_lv(Grade, Lv),
    cal_maxcost_energy(E + LevelNeedEnergy, HaveEnergy, Grade, ListLv).


cal_ascend_level_and_haveenergy(HaveEnergy, AscendEnergy, Grade, Level) ->
    #base_uranium_lv{energy = LevelNeedEnergy} = data_uranium:get_uranium_lv(Grade, Level),
    NewHaveEnergy = AscendEnergy + HaveEnergy,
    if
        AscendEnergy == 0 ->
            {Level, HaveEnergy};
        NewHaveEnergy >= LevelNeedEnergy ->  %会升级
            cal_ascend_level_and_haveenergy(0, AscendEnergy - (LevelNeedEnergy - HaveEnergy), Grade, Level + 1);
        true ->
            {Level, AscendEnergy + HaveEnergy}
    end.


%%升级
uranium_lv(Status, AutoNum)->
	#player_status{
        id=RoleID,
        figure = #figure{name=Name},
        role_uranium = RoleUranium
    } = Status,
    #role_uranium{
        grade = Grade,
        lv = Lv,
        % start_time = HTime,
        % quick_time = QTime
        have_energy = HaveEnergy
    }=RoleUranium,
    % Now   = utime:unixtime(),
    % Acc   = Now-HTime+QTime,
    [[{GoodTypeId, OneEnergy}]] = data_uranium:sel_uranium_kv(?MATERIAL_USE), %获取魂力升级材料
    [{GoodTypeId, GoodNum}] = lib_goods_api:get_goods_num(Status, [GoodTypeId]), %目前用户背包有多少材料


    CKList = [
        {check_max_lv,Lv,Grade},
        % {check_max_autonum, AutoNum},
        % {check_cost,Grade,Lv,Acc} %通过时间升级，舍弃
        {check_cost_enough, AutoNum, GoodNum}
    ],
    case util:check_lists(?MODULE,CKList) of
        {ok,Cost}->
            AscendEnergy = OneEnergy * Cost,
            MaxCostEnergy = cal_maxcost_energy(0, HaveEnergy, Grade, lists:seq(Lv, data_uranium:get_lv_max(Grade) - 1 )),  %当前阶最多需要多少能量
            {DelCost, NRoleUranium} =
            if
                MaxCostEnergy < AscendEnergy ->  %用不完就满级了
                RealCost = MaxCostEnergy div OneEnergy,
                ORoleUranium = RoleUranium#role_uranium{
                        lv = data_uranium:get_lv_max(Grade),
                        have_energy = 0
                    },
                {RealCost, ORoleUranium};

                true ->   %可以用完
                    {NewLevel, NewHaveEnergy} = cal_ascend_level_and_haveenergy(HaveEnergy, AscendEnergy, Grade, Lv),
                    ORoleUranium = RoleUranium#role_uranium{
                        lv = NewLevel,
                        have_energy = NewHaveEnergy
                    },
                    {Cost, ORoleUranium}
            end,

            % GoodStatus = lib_goods_do:get_goods_status(),
            % goods_del:delete_type_list_goods({GoodTypeId, DelCost}, GoodStatus),
            CostList = [{?TYPE_GOODS, GoodTypeId, DelCost}],
			case lib_goods_api:cost_object_list_with_check(Status, CostList, uranium_lv, "") of
                {false, Err, _} ->
					{false, Err};
				{true, Status1, _} ->
                    NStatus0 = Status1#player_status{role_uranium=NRoleUranium},
                    save_role_uranium(RoleID,NRoleUranium),

                    NStatus = lib_player:count_player_attribute(NStatus0),
                    lib_player:send_attribute_change_notify(NStatus, ?NOTIFY_ATTR),
                    % lib_log_api:log_uranium_upgrade(RoleID,Name,Grade,Lv,Grade,Lv+1),
                    NLv = NRoleUranium#role_uranium.lv,
                    lib_log_api:log_uranium_upgrade(RoleID,Name,Grade,Lv,Grade,NLv),
                    {ok,NStatus}
            end;

        {false,Err}->
        	{false,Err}
    end.



%%进阶
uranium_grade(Status)->
	#player_status{
        id=RoleID,
        role_uranium = RoleUranium,
        skill = StatusSkill,
        figure = #figure{name=Name,lv=RoleLv}
    } = Status,
    #role_uranium{
        grade = Grade,
        lv = Lv
    }=RoleUranium,
    % Now = utime:unixtime(),
    CKList = [
        {check_grade,Grade},
        {check_grade_lv,Grade,Lv},
        {check_condition,Grade,Status}
    ],
    case util:check_lists(?MODULE,CKList) of
        true->
            NGrade = Grade+1,
            #base_uranium_grade{name=UName}=data_uranium:get_uranium_grade(NGrade),
        	NRoleUranium = RoleUranium#role_uranium{
        		grade = NGrade,
        		lv = 0,
                have_energy = 0
        		% start_time = Now,
        		% init_time = Now,
                % quick_time = 0
        	},
        	save_role_uranium(RoleID,NRoleUranium),

            #status_skill{skill_list=SkillList} = StatusSkill,
            #base_uranium_grade{skills=USkills} = data_uranium:get_uranium_grade(NGrade),

            NSkillList = update_skills(SkillList,USkills),
            {SkillAttr, SkillPower} = lib_skill_attr:get_passive_skill_attr_and_power(NSkillList, RoleLv),
            HpResumeSpclAdd = lib_skill:count_hp_resume_spcl_add(RoleLv, NSkillList),
            NStatusSkill = StatusSkill#status_skill{
                skill_list = NSkillList
                ,hp_resume_spcl_add = HpResumeSpclAdd
                ,skill_power = SkillPower,skill_attr = SkillAttr
            },

            NStatus0 = Status#player_status{role_uranium=NRoleUranium,skill=NStatusSkill},
	        case USkills of
				[_|_] = SkillValue -> ok;
				_ -> SkillValue = []
	        end,
	        SkillValue =/= [] andalso lib_achievement_api:uranium_skill_event(Status, SkillValue),
            NStatus = lib_player:count_player_attribute(NStatus0),
            lib_player:send_attribute_change_notify(NStatus, ?NOTIFY_ATTR),
            lib_chat:send_TV({all}, ?MOD_URANIUM, 1, [Name,NGrade,UName]),

            mod_scene_agent:update(NStatus, [{battle_attr, NStatus#player_status.battle_attr}]),
            lib_log_api:log_uranium_upgrade(RoleID,Name,Grade,Lv,NGrade,0),
            lib_skill:send_my_skill_list(NStatus),
        	{ok,NStatus};
        {false,Err}->
        	{false,Err}
    end.

update_skills(SkillList,[])->
    SkillList;
update_skills(SkillList,[{Skill,Lv}|T])->
    update_skills(lists:keystore(Skill,1,SkillList,{Skill,Lv}),T).

% uranium_quick(Status)->
% 	#player_status{
%         id=RoleID,
%         role_uranium = RoleUranium
%     } = Status,
%     #role_uranium{
%         grade = Grade,
%         lv = Lv,
%         init_time = ITime,
%         start_time = _HTime,
%         quick_time = QTime
%     }=RoleUranium,
%     #base_uranium_lv{total=Total} = data_uranium:get_uranium_lv(Grade,Lv),
%     TailTime = ITime+Total-QTime,
%     Now = utime:unixtime(),
%     Remain = TailTime-Now,
%    	CKList = [
%         {check_max_lv,Lv,Grade},
%         {check_cost,Remain,Status}
%     ],
%     case util:check_lists(?MODULE,CKList) of
%         {ok,TmpStatus}->
%         	NRoleUranium = RoleUranium#role_uranium{quick_time=QTime+Remain},
%         	NStatus0 = TmpStatus#player_status{role_uranium=NRoleUranium},
%         	save_role_uranium(RoleID,NRoleUranium),

%             NStatus = lib_player:count_player_attribute(NStatus0),
%             lib_player:send_attribute_change_notify(NStatus, ?NOTIFY_ATTR),

%         	{ok,NStatus};
%         {false,Err}->
%         	{false,Err}
%     end.

%%进阶验证
check_grade(Status,Grade)->
	#base_uranium_grade{condition=Condition}=data_uranium:get_uranium_grade(Grade),
    NewCondition = [
        {Cond, Status} || Cond <- Condition
    ],
    check_list(NewCondition).

check_list([]) -> true;
check_list([H|L]) ->
    case check(H) of
        {false, Reason} ->
            {false, Reason};
        true ->
            check_list(L)
    end.

%% 检查玩家等级
check({{1, NeedLv}, Status}) ->
    #player_status{figure=#figure{lv=Lv}}=Status,
    case Lv>=NeedLv of
        true ->
            true;
        _ ->
            {false,?ERRCODE(err144_lv_unreach)}
    end;

%%检测爬塔
check({{2,NeedFloor}, Status}) ->
    MaxFloor = lib_dungeon_tower:get_pass_max_floor(Status),
    case MaxFloor>=NeedFloor of
    	true->
    		true;
    	_->
      		{false,?ERRCODE(err144_floor_unreach)}
    end;

%%检测玩家战力
check({{3,NeedPower}, Status}) ->
    #player_status{combat_power=RolePower}=Status,
    case RolePower>=NeedPower of
        true->
            true;
        _->
            {false,?ERRCODE(err144_power_unreach)}
    end;
%%检测经验副本
check({{4,NeedFloor}, Status}) ->
    RoleFloor = lib_dungeon_exp:get_sweep_wave(Status, 5001,0, 0, 0),
    case RoleFloor>=NeedFloor of
        true->
            true;
        _->
            {false,?ERRCODE(err144_expdun_floor_unreach)}
    end;
%%检测战魂星级
check({{5,NeedStars}, _Status}) ->
    AllWarSoul    = warsoul_api:get_all_warsoul_list(),
    RStars = lists:foldl(
        fun(GoodsInfo,Sum) ->
            Star = warsoul_api:get_warsoul_star(GoodsInfo),
            Sum+Star
        end, 0, AllWarSoul),
    case RStars>=NeedStars of
        true->
            true;
        _->
            {false,?ERRCODE(err144_warsoul_stars_unreach)}
    end;
% -------------------------------------
% ----------- wrote by jx-------------
% check({check_max_autonum, AutoNum}) ->  %一次可以使用升级材料的最高上限
%     if
%         AutoNum > ?MaxAutoNum ->
%             % {false, ?ERRCODE(err144_beyond_max_autonum)};
%             {false, ?ERRCODE(fail)};
%         true ->
%             true
%     end;
check({check_cost_enough, AutoNum, GoodNum}) -> %背包是否有足够物品可供消耗
    if
        GoodNum >= AutoNum ->
            {ok, AutoNum};
        GoodNum < AutoNum andalso GoodNum > 0 ->
            {ok, GoodNum};
        true ->
            % {false, ?ERRCODE(err144_material_error)}
            {false, ?ERRCODE(fail)}
    end;
% -------------------------------------
% -------------------------------------
% check({check_cost,Remain,Status})->
% 	case Remain=<60 of
% 		true->
% 			{false,?ERRCODE(err144_no_need_quick)};
% 		_->
% 			Value = util:ceil(Remain/300),
% 			Cost  = [{?TYPE_GOLD,?GOODS_ID_GOLD,Value}],
% 			case lib_goods_api:cost_object_list_with_check(Status, Cost, role_uranium, ["role_uranium_quick"]) of
% 		        {true,TmpStatus,_}->
%             		{ok,TmpStatus};
%             	{false,Err,_}->
%             		{false,Err}
%             end
%      end;
check({check_grade,Grade})->
	MaxGrade = data_uranium:get_max_grade(),
	case Grade>=MaxGrade of
		true->
			{false,?ERRCODE(err144_has_been_grade_max)};
		_->
			true
	end;
% check({check_cost,Grade,Lv,Acc})->
% 	#base_uranium_lv{
% 		need = Cost
% 	}=data_uranium:get_uranium_lv(Grade,Lv),
% 	case Acc>=Cost of
% 		true->
% 			{ok,Cost};
% 		_->
% 			{false,?ERRCODE(err144_need_wait_more_time)}
% 	end;
check({check_grade_lv,Grade,Lv})->
	LvMax = data_uranium:get_lv_max(Grade),
	case Lv>=LvMax of
		true->
			true;
		_->
			{false,?ERRCODE(err144_need_enough_lv)}
	end;
check({check_condition,Grade,Status})->
	check_grade(Status,Grade);
check({check_max_lv,Lv,Grade})->
	LvMax = data_uranium:get_lv_max(Grade),
	case Lv>=LvMax of
		true->
			{false,?ERRCODE(err144_has_been_lv_max)};
		_->
			true
	end.

save_role_uranium(RoleID,RoleUranium)->
	#role_uranium{
        grade = Grade,
        lv = Lv,
        have_energy = HaveEnergy
        % init_time = ITime,
        % start_time = HTime,
        % quick_time = QTime
    }=RoleUranium,
	% Sql = io_lib:format(?SQL_ROLE_URANIUM_REPLACE, [RoleID,Grade,Lv,ITime,HTime,QTime]),
    Sql = io_lib:format(?SQL_ROLE_URANIUM_REPLACE, [RoleID,Grade,Lv,HaveEnergy]),
    db:execute(Sql),
    ok.

%%获得属性
get_attr(Status)->
    #player_status{role_uranium=RoleUranium,figure=#figure{lv=RoleLv}}=Status,
    #role_uranium{grade=Grade,lv=Lv}=RoleUranium,
    case RoleLv >= data_module:get_module_open_lv(?MOD_URANIUM) of
        true->
            case data_uranium:get_uranium_lv(Grade,Lv) of
                #base_uranium_lv{attrs=Attrs}->
                    skip;
                _->
                    Attrs = []
            end,
            Attrs;
        _->
            []
    end.

calc_power(Status, AttrPower, BaseAttr) ->
    UraniumAttr = get_attr(Status),
    PartialAttr = attr_conv:to_attr_record(UraniumAttr),
    Power = lib_player_attr:calc_attr_power_partial(AttrPower, BaseAttr, PartialAttr),
    #player_status{role_uranium=RoleUranium}=Status,
    {Status#player_status{role_uranium=RoleUranium#role_uranium{power=Power}}, 0}.
