%% -----------------------------------------------------
%% @author  :ljy
%% moudle   :lib_seven_days_goal.erl
%% desc     :七日目标
%% time     :2020.12.21
%% ------------------------------------------------------
-module(lib_seven_days_goal).

-export([
    get_task_info/1
    , receive_task_reward/4
    , receive_score_reward/3
    , receive_skill_reward/3
    , finish_dungeon_task/4
    , async_event/4
    , finish_task/4
    , finish_task/5                %% 完成任务触发
    , do_finish_task/3
    , do_finish_task/4
    , do_finish_task/5
    , offline_do_finish_task/4
    , handle_event/2
    , kill_boss/4
    , do_kill_boss/4
    , calc_red_equip_num/1
    , wear_red_equip_event/1
    , login_load_data/1
    , special_task_handle/3
    , gm_add_login_day/2
    , special_task_init/5
]).

-include("seven_day_goal.hrl").
-include("server.hrl").
-include("errcode.hrl").
-include("predefine.hrl").
-include("rec_event.hrl").
-include("def_event.hrl").
-include("def_fun.hrl").
-include("figure.hrl").
-include("def_module.hrl").
-include("common.hrl").
-include("skill.hrl").
-include("equipment.hrl").
-include("dungeon.hrl").
-include("rec_recharge.hrl").
-include("def_goods.hrl").

%% 获取界面展示信息
get_task_info(Player) ->
    #player_status{sid = Sid, seven_days_goal = SevenDaysGoal} = Player,
    #seven_days_goal{
        days = LoginDays,
        open_time = OpenTime,
        score = Score,
        task_reward = TaskReward,
        score_reward = ScoreReward,
        skill_reward = SkillReward,
        task_status = TaskStatus
    } = SevenDaysGoal,
    DiffDays = utime:day_span(OpenTime),
    DaysList = data_seven_goal:get_all_days(),
    MaxDay = lists:max(DaysList),
    if
        ?ACT_OPEN_DAYS >= DiffDays ->
            F = fun({{Days, ModId, SubId}, Progress}, Acc) ->
                IsReceive = lists:member({Days, ModId, SubId}, TaskReward),
                ReceiveState = ?IF(IsReceive == true, 1, 0),
                [{Days, ModId, SubId, Progress, ReceiveState} | Acc]
                end,
            TaskState = lists:foldl(F, [], TaskStatus),
            LeftTime = utime:that_day_after(OpenTime, MaxDay),
            RealTime = utime:that_day_after(OpenTime, ?ACT_OPEN_DAYS),
            {ok, Bin} = pt_176:write(17600, [LoginDays, Score, LeftTime, RealTime, TaskState, ScoreReward, SkillReward]),
            lib_server_send:send_to_sid(Sid, Bin);
        true -> skip
    end.

%% 领取任务奖励
receive_task_reward(Ps, LoginDays, ModId, SubId) ->
    #player_status{sid = Sid, id = RoleId, seven_days_goal = SevenDaysGoal, figure = Figure} = Ps,
    #figure{name = Name, lv = Lv} = Figure,
    #seven_days_goal{
        score = Score,
        open_time = OpenTime,
        task_reward = TaskReward,
        task_status = TaskStatus
    } = SevenDaysGoal,
    CheckList = [
        {is_open, OpenTime},
        {is_receive, LoginDays, ModId, SubId, TaskReward},
        {progress, LoginDays, ModId, SubId, TaskStatus}
    ],
    case check_list(CheckList) of
        true ->
            #base_seven_goal_task{reward = Reward} = data_seven_goal:get_task_cfg(LoginDays, ModId, SubId),

            NewTaskReward = [{LoginDays, ModId, SubId} | TaskReward],
            NewSevenDaysGoal = SevenDaysGoal#seven_days_goal{task_reward = NewTaskReward},
            Ps1 = Ps#player_status{seven_days_goal = NewSevenDaysGoal},
            SQL = io_lib:format(?SQL_UPDATE_TASK_REWARD, [util:term_to_bitstring(NewTaskReward), RoleId]),
            db:execute(SQL),
            NewPs = lib_goods_api:send_reward(Ps1, Reward, seven_receive_reward),
            OpenDays = util:get_open_day(),
            lib_log_api:log_seven_days_goal(RoleId, 1, Name, Lv, Score, OpenDays, [LoginDays, ModId, SubId], Reward),
            {ok, Bin} = pt_176:write(17601, [?SUCCESS, LoginDays, ModId, SubId]),
            lib_server_send:send_to_sid(Sid, Bin),
            {ok, NewPs};
        {false, ErrorCode} ->
            {ok, Bin} = pt_176:write(17601, [ErrorCode, LoginDays, ModId, SubId]),
            lib_server_send:send_to_sid(Sid, Bin)
    end.

%% 领取积分奖励
receive_score_reward(Ps, Type, TargetScore) ->
    #player_status{id = RoleId, sid = Sid, seven_days_goal = SevenDaysGoal, figure = Figure} = Ps,
    #figure{name = Name, lv = Lv} = Figure,
    #seven_days_goal{
        open_time = OpenTime,
        score = Score,
        score_reward = ScoreReward
    } = SevenDaysGoal,
    CheckList = [
        {is_open, OpenTime},
        {is_receive, TargetScore, ScoreReward},
        {is_enough, Score, TargetScore},
        {is_right_score_data, TargetScore}
    ],
    case check_list(CheckList) of
        true ->
            #base_seven_goal_score{reward = Reward} = data_seven_goal:get_score_cfg(TargetScore),

            NewScoreReward = [TargetScore | ScoreReward],
            NewSevenDaysGoal = SevenDaysGoal#seven_days_goal{score_reward = NewScoreReward},
            Ps1 = Ps#player_status{seven_days_goal = NewSevenDaysGoal},
            SQL = io_lib:format(?SQL_UPDATE_SCORE_REWARD, [util:term_to_bitstring(NewScoreReward), RoleId]),
            db:execute(SQL),
            NewPs = lib_goods_api:send_reward(Ps1, Reward, seven_receive_reward),
            OpenDays = util:get_open_day(),
            lib_log_api:log_seven_days_goal(RoleId, 2, Name, Lv, Score, OpenDays, [TargetScore], Reward),
            {ok, Bin} = pt_176:write(17602, [?SUCCESS, Type, TargetScore]),
            lib_server_send:send_to_sid(Sid, Bin),
            {ok, NewPs};
        {false, ErrorCode} ->
            {ok, Bin} = pt_176:write(17602, [ErrorCode, Type, TargetScore]),
            lib_server_send:send_to_sid(Sid, Bin)
    end.

%% 领取技能奖励
receive_skill_reward(Ps, Type, Days) ->
    #player_status{id = RoleId, sid = Sid, seven_days_goal = SevenDaysGoal, figure = Figure} = Ps,
    #figure{name = Name, lv = Lv} = Figure,
    #seven_days_goal{
        score = Score,
        open_time = OpenTime,
        days = LoginDays,
        task_status = TaskStatus,
        skill_reward = SkillReward
    } = SevenDaysGoal,
    CheckList = [
        {is_open, OpenTime},
        {is_receive, Days, SkillReward},
        {is_enough, LoginDays, Days},
        {is_right_skill_data, Days},
        {is_finish_all_task, Days, TaskStatus}
    ],
    case check_list(CheckList) of
        true ->
            #base_seven_skill_reward{skill_reward = SkillId} = data_seven_goal:get_skill_reward_cfg(Days),
            Ps1 = add_skill(SkillId, Ps),
            NewSkillReward = [Days | SkillReward],
            NewSevenDaysGoal = SevenDaysGoal#seven_days_goal{skill_reward = NewSkillReward},
            NewPs = Ps1#player_status{seven_days_goal = NewSevenDaysGoal},
            SQL = io_lib:format(?SQL_UPDATE_SKILL_REWARD, [util:term_to_bitstring(NewSkillReward), RoleId]),
            db:execute(SQL),
            OpenDays = util:get_open_day(),
            lib_log_api:log_seven_days_goal(RoleId, 3, Name, Lv, Score, OpenDays, [Days], [SkillId]),
            {ok, Bin} = pt_176:write(17602, [?SUCCESS, Type, Days]),
            lib_server_send:send_to_sid(Sid, Bin),
            {ok, NewPs};
        {false, ErrorCode} ->
            {ok, Bin} = pt_176:write(17602, [ErrorCode, Type, Days]),
            lib_server_send:send_to_sid(Sid, Bin)
    end.

add_skill(SkillId, Status) ->
    #player_status{figure = Figure, skill = Sk} = Status,
    #figure{turn = Turn, lv = RoleLv} = Figure,
    SkillList = Sk#status_skill.skill_list,
    case lists:keyfind(SkillId, 1, SkillList) of
        false ->
            case data_skill:get(SkillId, 1) of
                #skill{is_anger = IsAnger, skill_link = SkillLink, type = SkillType} ->
                    Status1 = lib_skill:update_status_skill(Status, SkillId, 1, SkillLink, 0),
                    %% 被动技能属性加成 那
                    Status2 = case SkillType of
                                  ?SKILL_TYPE_PASSIVE -> lib_skill:update_skill_attribute_for_ps(Status1);
                                  _ -> Status1
                              end,
                    %% 人物属性计算
                    #player_status{skill = SkillStatus} = Status2,
                    #status_skill{skill_list = SkillList2} = SkillStatus,
                    {SkillAttr, SkillPower} = lib_skill_attr:get_passive_skill_attr_and_power(SkillList2, RoleLv),
                    NSkillStatus = SkillStatus#status_skill{skill_attr = SkillAttr, skill_power = SkillPower},
                    Status3 = Status2#player_status{skill = NSkillStatus},
                    Status4 = lib_player:count_player_attribute(Status3),
                    mod_scene_agent:update(Status4, [{battle_attr, Status4#player_status.battle_attr}]),
                    lib_player:send_attribute_change_notify(Status4, ?NOTIFY_ATTR),
                    lib_skill:send_my_skill_list(Status4),
                    AddSkills = [{SkillId, SkillType, IsAnger}],
                    Status5 = quickbar_api:after_auto_learn_skill(
                        Status4, Turn, AddSkills, login
                    ),
                    Status5;
                _ -> Status
            end;
        _ ->
            Status
    end.

%% 副本结束后触发
finish_dungeon_task(Player, ?MOD_DUNGEON, 2, _Count) ->
    {ok, Player};
%%    % 经验副本特殊处理，因为返回的波数是最大通关波数
%%    #player_status{seven_days_goal = SevenDaysGoal} = Player,
%%    #seven_days_goal{other_data = OtherData} = SevenDaysGoal,
%%    case lists:keyfind(exp_dun_wave, 1, OtherData) of
%%        {_, Ware} when Count > Ware ->
%%            NewOtherData = lists:keystore(exp_dun_wave, 1, OtherData, {exp_dun_wave, Count}),
%%            Times = Count - Ware;
%%        _ ->
%%            NewOtherData = OtherData,
%%            Times = 1
%%    end,
%%    NewSevenDaysGoal = SevenDaysGoal#seven_days_goal{other_data = NewOtherData},
%%    NewPlayer = Player#player_status{seven_days_goal = NewSevenDaysGoal},
%%    do_finish_task(NewPlayer, ?MOD_DUNGEON, 2, Times);
finish_dungeon_task(Player, _ModId, _SubId, _Count) ->
    {ok, Player}.
%%    if
%%        Count =:= 0 -> Times = 1;
%%        true -> Times = Count
%%    end,
%%    DayList = data_seven_goal:get_task_days(ModId, SubId),
%%    if
%%        DayList =:= [] -> {ok, Player};
%%        true -> do_finish_task(Player, ModId, SubId, Times)
%%    end.

%% 异步玩家进程触发
async_event(RoleId, Mod, Fun, Args) when is_integer(RoleId) ->
    lib_player:apply_cast(RoleId, ?APPLY_CAST_SAVE, Mod, Fun, Args);
async_event(_PlayerId, _M, _F, _A) -> skip.

%% 击杀个人、赏金、废都boss(可指定击杀特定boss)
kill_boss(_RoleId, _ModId, _SubId, _BossId) ->
    ok.
    % lib_player:apply_cast(RoleId, ?APPLY_CAST_SAVE, ?MODULE, do_kill_boss, [ModId, SubId, BossId]).

do_kill_boss(Player, _ModId, _SubId, _BossId) ->
    {ok, Player}.
%%    #player_status{id = RoleId, sid = Sid, seven_days_goal = SevenDaysGoal, figure = Figure, recharge_statistic = RechargeStatistic} = Player,
%%    #figure{name = Name, lv = Lv} = Figure,
%%    #role_recharge_statistic{recency = R, frequency = F, monetary = M, top = T} = RechargeStatistic,
%%    #seven_days_goal{
%%        open_time = OpenTime,
%%        days = LoginDays,
%%        score = Score,
%%        task_status = TaskStatus
%%    } = SevenDaysGoal,
%%    DayList = data_seven_goal:get_task_days(ModId, SubId),
%%    Fun = fun(Day, {Tasks1, Score1}) when LoginDays >= Day ->
%%        % 配置中有boss关键字的需要指定杀死某只怪，没有配置boss关键字的随便杀死某只怪即可完成任务
%%        #base_seven_goal_task{condition = Cond} = data_seven_goal:get_task_cfg(Day, ModId, SubId),
%%        case lists:keyfind(boss, 1, Cond) of
%%            {_, Id} when BossId =/= Id ->
%%                {Tasks1, Score1};
%%            _ ->
%%                case lists:keyfind({Day, ModId, SubId}, 1, Tasks1) of
%%                    {_, Progress} ->
%%                        skip;
%%                    _ ->
%%                        Progress = 0
%%                end,
%%                case lists:keyfind(limit_times, 1, Cond) of
%%                    {_, Times} when Times > Progress ->
%%                        RealProgress = ?IF(Times >= Progress + 1, Progress + 1, Times),
%%                        NewTasks2 = lists:keystore({Day, ModId, SubId}, 1, Tasks1, {{Day, ModId, SubId}, RealProgress}),
%%                        NewScore2 = ?IF(RealProgress >= Times, Score1 + 1, Score1),
%%                        SQL = io_lib:format(?SQL_REPLACE_INTO_SEVEN_DAYS_TASK, [RoleId, Day, ModId, SubId, RealProgress]),
%%                        db:execute(SQL),
%%                        lib_log_api:log_seven_goal_task(RoleId, Name, Lv, [R,F,M,T], Day, [ModId, SubId, RealProgress]),
%%                        {ok, Bin} = pt_176:write(17603, [NewScore2, Day, ModId, SubId, RealProgress]),
%%                        lib_server_send:send_to_sid(Sid, Bin),
%%                        {NewTasks2, NewScore2};
%%                    _ ->
%%                        {Tasks1, Score1}
%%                end
%%        end;
%%    (_Day, {Tasks1, Score1}) ->
%%        {Tasks1, Score1}
%%    end,
%%    % 功能已开放30天后不再触发
%%    DiffDays = utime:day_span(OpenTime),
%%    if
%%        ?ACT_OPEN_DAYS >= DiffDays ->
%%            {NTaskStatus,NScore} = lists:foldl(Fun, {TaskStatus, Score}, DayList),
%%            NScore =/= Score andalso db:execute(io_lib:format(?SQL_UPDATE_TASK_STATUS, [NScore, RoleId])),
%%            NewSevenDaysGoal = SevenDaysGoal#seven_days_goal{task_status = NTaskStatus, score = NScore},
%%            NewPlayer = Player#player_status{seven_days_goal = NewSevenDaysGoal},
%%            {ok, NewPlayer};
%%        true -> {ok, Player}
%%    end.

%% 完成任务触发
%% 1. 当天任务直接触发
%% 2. 非当天任务需要判断是否可以提前触发
%% (完成当天的任务才会加积分)
%% IsPreCalc - 是否提前完成(默认为false)
finish_task(RoleId, ModId, SubId, Count) ->
    finish_task(RoleId, ModId, SubId, Count, false).
finish_task(RoleId, ModId, SubId, Count, IsPreCalc) ->
    lib_player:apply_cast(RoleId, ?APPLY_CAST_SAVE, ?MODULE, do_finish_task, [ModId, SubId, Count, IsPreCalc]),
    ok.

do_finish_task(Player, ModId, SubId) ->
    do_finish_task(Player, ModId, SubId, false).

do_finish_task(Player, ModId, SubId, IsPreCalc) ->
    do_finish_task(Player, ModId, SubId, 1, IsPreCalc).

do_finish_task(Player, ModId, SubId, Count, IsPreCalc) ->
    #player_status{id = RoleId, sid = Sid, seven_days_goal = SevenDaysGoal, figure = Figure, recharge_statistic = RechargeStatistic} = Player,
    #figure{name = Name, lv = Lv} = Figure,
    #seven_days_goal{
        open_time = OpenTime,
        days = LoginDays,
        score = Score,
        task_status = TaskStatus,
        task_reward = TaskRewards
    } = SevenDaysGoal,
    DiffDays = utime:day_span(OpenTime),
    % OpenDay  = util:get_open_day(),
    if
        ?ACT_OPEN_DAYS >= DiffDays ->
            % 完成任务增加进度值
            #role_recharge_statistic{recency = R, frequency = F, monetary = M, top = T} = RechargeStatistic,
            Fun = fun(Day, {Acc, Add}) ->
                %% 已经领取了奖励就不需要触发了
                CanAdd = case lists:member({Day, ModId, SubId}, TaskRewards) of
                             true ->
                                 false;
                             _ ->
                                 case IsPreCalc of
                                     true -> true;
                                     _ -> DiffDays >= Day
                                 end
                          end,
                case CanAdd of
                    false -> {Acc, Add};
                    _ ->
                        case lists:keyfind({Day, ModId, SubId}, 1, TaskStatus) of
                            {_, Progress} -> skip;
                            _ -> Progress = 0
                        end,
                        case data_seven_goal:get_task_cfg(Day, ModId, SubId) of
                            #base_seven_goal_task{name = TaskName, condition = Cond} -> ok;
                            _ -> TaskName = "", Cond = []
                        end,
                        %% 特殊任务进度达到了，还可以变动
                        IsSpecialTask = lists:member({ModId, SubId}, ?SPECIAL_TASK_TYPE),
                        case lists:keyfind(limit_times, 1, Cond) of
                            {_, Times} when Progress >= Times, IsSpecialTask == false ->
                                {Acc, Add};
                            {_, Times} ->
                                %% 先记录天数，至于Score是否统计则根据开放天数来决定
                                %% 区分替代型和迭代型的任务(装备和宠物任务特殊处理)
                                RealProgress = if
                                                   {Day, ModId, SubId} == {1, 152, 8} ->
                                                       EquipInfos = equipment_api:get_equipment_wear_info(),
                                                       Num = calc_equip_num(1, EquipInfos),
                                                       ?IF(Times >= Num, Num, Times);
                                                   {Day, ModId, SubId} == {2, 152, 9} ->
                                                       EquipInfos = equipment_api:get_equipment_series_rise_info(),
                                                       Num = calc_series_equip_num(1, EquipInfos),
                                                       ?IF(Times >= Num, Num, Times);
                                                   {Day, ModId, SubId} == {4, 152, 9} ->
                                                       EquipInfos = equipment_api:get_equipment_series_rise_info(),
                                                       Num = calc_series_equip_num(2, EquipInfos),
                                                       ?IF(Times >= Num, Num, Times);
                                                   {ModId, SubId} == {163, 0} ->
                                                        Count1 = max(Progress, Count),
                                                        ?IF(Times >= Count1, Count1, Times);
                                                   true ->
                                                       case lists:member({ModId, SubId}, ?REPLACE_TASK_TYPE) of
                                                           true ->
                                                               ?IF(Times >= Count, Count, Times);
                                                           _ ->
                                                               ?IF(Times >= Progress + Count, Progress + Count, Times)
                                                       end
                                               end,
                                NewAcc = lists:keystore({Day, ModId, SubId}, 1, Acc, {{Day, ModId, SubId}, RealProgress}),
                                RealScore = case LoginDays >= Day of
                                                true -> ?IF(RealProgress >= Times, Add + 1, Add);
                                                _ -> Add
                                            end,
                                SQL = io_lib:format(?SQL_REPLACE_INTO_SEVEN_DAYS_TASK, [RoleId, Day, ModId, SubId, RealProgress]),
                                db:execute(SQL),
                                lib_log_api:log_seven_goal_task(RoleId, Name, Lv, [R,F,M,T], Day, [ModId, SubId, RealProgress]),
                                RealProgress >= Times andalso ta_agent_fire:seven_goal_task(Player, [Day, ModId, SubId, TaskName]),
                                case LoginDays >= Day of
                                    true ->
                                        {ok, Bin} = pt_176:write(17603, [RealScore, Day, ModId, SubId, RealProgress]),
                                        lib_server_send:send_to_sid(Sid, Bin);
                                    _ -> ignore
                                end,
                                {NewAcc, RealScore};
                            _ ->
                                {Acc, Add}
                        end
                end end,
            DayList = data_seven_goal:get_task_days(ModId, SubId),
            {NewTaskStatus, _Score1} = lists:foldl(Fun, {TaskStatus, Score}, DayList),
            %% 全量计算比较好；增量计算，当策划改配置有可能引发问题
            NewScore = calc_all_finish_task(LoginDays, LoginDays, NewTaskStatus),
            NewScore =/= Score andalso db:execute(io_lib:format(?SQL_UPDATE_TASK_STATUS, [NewScore, RoleId])),
            NewSevenDaysGoal = SevenDaysGoal#seven_days_goal{task_status = NewTaskStatus, score = NewScore},
            NewPlayer = Player#player_status{seven_days_goal = NewSevenDaysGoal},
            {ok, NewPlayer};
        true ->
	        {ok, Player}
    end.

%% 根据套装数计算紫色以上装备收集数
calc_equip_num(Series, EquipInfos) ->
    F = fun(EquipInfo, SumNum) ->
        case EquipInfo of
            {Series, Color, Num} when Color >= ?PURPLE ->
                SumNum + Num;
            _ ->
                SumNum
        end end,
    lists:foldl(F, 0, EquipInfos).

calc_series_equip_num(Series, EquipInfos) ->
    EquipList = maps:get(Series, EquipInfos, []),
    F = fun(EquipInfo, SumNum) ->
        case EquipInfo of
            {Lv, Num} when Lv >= 2 ->
                SumNum + Num;
            _ ->
                SumNum
        end end,
    lists:foldl(F, 0, EquipList).

%% 玩家离线时完成任务
offline_do_finish_task(RoleId, ModId, SubId, Count) ->
    DayList = data_seven_goal:get_task_days(ModId, SubId),
    SQL = io_lib:format(?SQL_SELECT_TIME_AND_SCORE, [RoleId]),
    case db:get_row(SQL) of
        [OpenTime, Score] ->
            DiffDays = utime:day_span(OpenTime),
            if
                ?ACT_OPEN_DAYS >= DiffDays ->
                    SQL2 = io_lib:format(?SQL_SELECT_PART_TASK, [RoleId, ModId, SubId]),
                    case db:get_all(SQL2) of
                        [] ->
                            TaskStatus = [];
                        TaskInfo ->
                            TaskStatus = [{{Day, ModId2, SubId2}, Progress} || [Day, ModId2, SubId2, Progress] <- TaskInfo]
                    end,
                    LoginDays = ?IF(DiffDays >= 7, 7, DiffDays),
                    SQL3 = io_lib:format(?SQL_SELECT_RFMT, [RoleId]),
                    case db:get_row(SQL3) of
                        [Name,Lv,R,F,M,T] when is_integer(R) ->
                            skip;
                        [Name,Lv,_,_,_,_] ->
                            R = F = M = T = 0;
                        [] ->
                            Name = <<>>,Lv = 0,
                            R = F = M = T = 0
                    end,
                    Fun = fun(Day, {Acc, Add}) when LoginDays >= Day ->
                            #base_seven_goal_task{condition = Cond} = data_seven_goal:get_task_cfg(Day, ModId, SubId),
                            case lists:keyfind({Day, ModId, SubId}, 1, TaskStatus) of
                                {_, Progress} ->
                                    skip;
                                _ ->
                                    Progress = 0
                            end,
                            case lists:keyfind(limit_times, 1, Cond) of
                                {_, Times} when Progress >= Times ->
                                    {Acc, Add};
                                {_, Times} ->
                                    RealProgress = ?IF(Times >= Progress + Count, Progress + Count, Times),
                                    NewAcc = lists:keystore({Day, ModId, SubId}, 1, Acc, {{Day, ModId, SubId}, RealProgress}),
                                    RealScore = ?IF(RealProgress >= Times, Add + 1, Add),
                                    SQL4 = io_lib:format(?SQL_REPLACE_INTO_SEVEN_DAYS_TASK, [RoleId, Day, ModId, SubId, RealProgress]),
                                    db:execute(SQL4),
                                    lib_log_api:log_seven_goal_task(RoleId, Name, Lv, [R,F,M,T], Day, [ModId, SubId, RealProgress]),
                                    {NewAcc, RealScore};
                                _ -> {Acc, Add}
                            end;
                        (_Day, {Acc, Add}) ->
                            {Acc, Add}
                          end,
                    {NewTaskStatus, _Score1} = lists:foldl(Fun, {TaskStatus, Score}, DayList),
                    NewScore = calc_all_finish_task(LoginDays, LoginDays, NewTaskStatus),
                    NewScore =/= Score andalso db:execute(io_lib:format(?SQL_UPDATE_TASK_STATUS, [NewScore, RoleId])),
                    ok;
                true -> skip
            end;
        [] ->
            skip
    end.

%% 计算玩家身上红装数量
calc_red_equip_num(Player) ->
    #player_status{equipment = StatusEquipment} = Player,
    #equipment{equipment_series = NewEquipmentSeries} = StatusEquipment,
    List = equipment_api:get_equipment_empower_info(NewEquipmentSeries),
    Count = lists:foldl(fun({_, Num}, Acc) -> Acc + Num end, 0, List),
    Count.

%% 激活红装
wear_red_equip_event(Player) ->
    {ok, Player}.
%%    #player_status{seven_days_goal = SevenDaysGoal} = Player,
%%    #seven_days_goal{
%%        open_time = OpenTime,
%%        other_data = OtherData
%%    } = SevenDaysGoal,
%%    DiffDays = utime:day_span(OpenTime),
%%    if
%%        DiffDays > ?ACT_OPEN_DAYS -> {ok, Player};
%%        true ->
%%            Num = calc_red_equip_num(Player),
%%            case lists:keyfind(red_equip, 1, OtherData) of
%%                {_, RedNum} when Num > RedNum ->
%%                    NewOtherData = lists:keystore(red_equip, 1, OtherData, {red_equip, Num}),
%%                    NewSevenDaysGoal = SevenDaysGoal#seven_days_goal{other_data = NewOtherData},
%%                    NewPlayer = Player#player_status{seven_days_goal = NewSevenDaysGoal},
%%                    do_finish_task(NewPlayer, ?MOD_EQUIP, 5, Num - RedNum);
%%                _ -> {ok, Player}
%%            end
%%    end.

%% 加载数据
login_load_data(Player) ->
    #player_status{id = RoleId} = Player,
    SQL = io_lib:format(?SQL_SELECT_SEVEN_DAYS_GOAL, [RoleId]),
    case db:get_row(SQL) of
        [OpenTime, Days, Score, TaskReward, ScoreReward, SkillReward, OtherData0] ->
            SQL2 = io_lib:format(?SQL_SELECT_SEVEN_DAYS_TASK, [RoleId]),
            case db:get_all(SQL2) of
                [] -> TaskStatus = [];
                TaskInfo ->
                    TaskStatus = [{{Day, ModId, SubId}, Progress} || [Day, ModId, SubId, Progress] <- TaskInfo]
            end,
            LoginDays = utime:day_span(OpenTime),
            MaxDay = ?ACT_OPEN_DAYS,
            OtherData = util:bitstring_to_term(OtherData0),
            %% 登录是否最好重新计算一次？(以前做法是跨天才刷新) TODO
            if
                MaxDay =/= Days andalso LoginDays > Days andalso MaxDay >= LoginDays ->
                    NewScore = calc_all_finish_task(Days, LoginDays, TaskStatus),
                    % {NewTaskStatus, AddScore2} = special_task_init(Player, Days, LoginDays, NewTaskStatus0, OtherData),
                    SQL3 = io_lib:format(?SQL_UPDATE_LOGIN_DAY, [LoginDays, NewScore, RoleId]),
                    db:execute(SQL3);
                true ->
                    NewScore = Score
            end,
            SevenDaysGoal =
                #seven_days_goal{
                    open_time = OpenTime,
                    days = LoginDays,
                    score = NewScore,
                    task_reward = util:bitstring_to_term(TaskReward),
                    score_reward = util:bitstring_to_term(ScoreReward),
                    skill_reward = util:bitstring_to_term(SkillReward),
                    task_status = TaskStatus,
                    other_data = OtherData
                },
            Player#player_status{seven_days_goal = SevenDaysGoal};
        [] ->
            init_data(Player)
    end.

%% 统计完成的任务进度（这里暂时先全量计算，如果任务多则转用增量的开放任务统计）
calc_all_finish_task(_Days, LoginDays, TaskStatus) ->
    DayList = if
                  LoginDays >= 7 ->
                      lists:seq(1, 7);
                  true ->
                      lists:seq(1, LoginDays)
              end,
    TaskList = collect_task(DayList, []),
    Fun = fun({Day, ModId, SubId}, AccScore) ->
        case data_seven_goal:get_task_cfg(Day, ModId, SubId) of
            #base_seven_goal_task{condition = Cond} ->
                case lists:keyfind(limit_times, 1, Cond) of
                    {_, Times} ->
                        case lists:keyfind({Day, ModId, SubId}, 1, TaskStatus) of
                            {_, FinTimes} -> ok;
                            _ -> FinTimes = 0
                        end,
                        RealProgress = ?IF(Times >= FinTimes, FinTimes, Times),
                        RealScore = ?IF(RealProgress >= Times, AccScore + 1, AccScore),
                        RealScore;
                    _ ->
                        AccScore
                end;
            _ ->
                AccScore
        end end,
    lists:foldl(Fun, 0, TaskList).

init_data(Player) ->
    #player_status{figure = Figure} = Player,
    #figure{id = RoleId, turn = Turn} = Figure,
    [DunId | _] = data_dungeon:get_ids_by_type(?DUNGEON_TYPE_EXP),
    SQL = io_lib:format(?SQL_SELECT_EXP_DUN_REC, [RoleId, DunId]),
    case db:get_one(SQL) of
        null -> Ware = 1;
        BinStr ->
            Rec = util:bitstring_to_term(BinStr),
            case lists:keyfind(?DUNGEON_REC_MAX_SCORE, 1, Rec) of
                {_, Ware} ->
                    skip;
                _ ->
                    Ware = 1
            end
    end,
    LoginDays = 1,
    F = fun({Days, ModId, SubId}, {Acc, Add}) ->
        if
            LoginDays >= Days andalso ModId =:= ?MOD_TRANSFORM andalso Turn >= SubId ->
                % [Diff|_] = data_seven_goal:get_task_all_diff(Days, ModId, SubId),
                SQL2 = io_lib:format(?SQL_REPLACE_INTO_SEVEN_DAYS_TASK, [RoleId, Days, ModId, SubId, 1]),
                db:execute(SQL2),
                {[{{Days, ModId, SubId}, 1} | Acc], Add + 1};
            true -> {Acc, Add}
        end
        end,
    TaskList = data_seven_goal:get_all_task_id(),
    {TaskStatus, AddScore} = lists:foldl(F, {[], 0}, TaskList),
    NowTime = utime:unixtime(),
    RedNum = calc_red_equip_num(Player),

    OtherData = [{red_equip, RedNum}, {exp_dun_wave, Ware}, {equipment_strength, 0}],
    SQL3 = io_lib:format(?SQL_REPLACE_INTO_SEVEN_DAYS_GOAL,
        [RoleId, NowTime, LoginDays, AddScore, util:term_to_bitstring(OtherData)]),
    db:execute(SQL3),
    SevenDaysGoal = #seven_days_goal{
        open_time = NowTime,
        days = LoginDays,
        score = AddScore,
        task_reward = [],
        score_reward = [],
        skill_reward = [],
        task_status = TaskStatus,
        other_data = OtherData
    },
    Player#player_status{seven_days_goal = SevenDaysGoal}.


%% --------------------------------------------------------------------------------------------------------
%% 特殊任务-转生，功能天数开放后，需要统计已转生次数
update_data(RoleId, Turn, Days, DiffDays, TaskStatus) ->
    ModId = ?MOD_TRANSFORM,
    F = fun(Day, {Acc, AddScore}) ->
        SubList = data_seven_goal:get_sub_ids(Day, ModId),
        F2 = fun(Sub, {Acc2, Add}) when Turn >= Sub ->
            % [Diff|_] = data_seven_goal:get_task_all_diff(Day, ModId, Sub),
            SQL = io_lib:format(?SQL_REPLACE_INTO_SEVEN_DAYS_TASK, [RoleId, Day, ModId, Sub, 1]),
            db:execute(SQL),
            NewAcc = lists:keystore({Day, ModId, Sub}, 1, Acc2, {{Day, ModId, Sub}, 1}),
            {NewAcc, Add + 1};
            (_Sub, {Acc2, Add}) ->
                {Acc2, Add}
             end,
        {NewAcc, Add} = lists:foldl(F2, {Acc, 0}, SubList),
        {NewAcc, AddScore + Add}
        end,
    DayList =
        if
            Days >= 7 ->
                [];
            DiffDays >= 7 ->
                lists:seq(Days + 1, 7);
            true ->
                lists:seq(Days + 1, DiffDays)
        end,
    lists:foldl(F, {TaskStatus, 0}, DayList).

%% 跨天时处理特殊任务，这类任务在功能开启时就开始计数任务完成次数，等待任务开放出来时需要更新任务进度(暂时废弃)
special_task_init(Player, Days, DiffDays, TaskStatus, OtherData) ->
    #player_status{id = RoleId, figure = Figure, recharge_statistic = RechargeStatistic} = Player,
    #role_recharge_statistic{recency = R, frequency = F, monetary = M, top = T} = RechargeStatistic,
    #figure{name = Name, lv = Lv} = Figure,
    case lists:keyfind(equipment_strength, 1, OtherData) of
        {_, FinTimes} ->
            skip;
        _ ->
            FinTimes = 0
    end,
    Fun = fun({Day, ModId, SubId}, {Acc, AddScore}) when ModId == ?MOD_EQUIP andalso SubId == 1 ->
        #base_seven_goal_task{name = TaskName, condition = Cond} = data_seven_goal:get_task_cfg(Day, ModId, SubId),
        case lists:keyfind(limit_times, 1, Cond) of
            {_, Times} ->
                RealProgress = ?IF(Times >= FinTimes, FinTimes, Times),
                NewAcc = lists:keystore({Day, ModId, SubId}, 1, Acc, {{Day, ModId, SubId}, RealProgress}),
                RealScore = ?IF(RealProgress >= Times, AddScore + 1, AddScore),
                SQL = io_lib:format(?SQL_REPLACE_INTO_SEVEN_DAYS_TASK, [RoleId, Day, ModId, SubId, RealProgress]),
                db:execute(SQL),
                lib_log_api:log_seven_goal_task(RoleId, Name, Lv, [R,F,M,T], Day, [ModId, SubId, RealProgress]),
                RealProgress >= Times andalso ta_agent_fire:seven_goal_task(Player, [Day, ModId, SubId, TaskName, 0]),
                {NewAcc, RealScore};
            _ ->
                {Acc, AddScore}
        end;
        (_, {Acc, AddScore}) ->
            {Acc, AddScore}
          end,
    DayList =
        if
            Days >= 7 ->
                [];
            DiffDays >= 7 ->
                lists:seq(Days + 1, 7);
            true ->
                lists:seq(Days + 1, DiffDays)
        end,
    TaskList = collect_task(DayList, []),
    lists:foldl(Fun, {TaskStatus, 0}, TaskList).

collect_task([], TaskList) ->
    TaskList;
collect_task([Day|DayList], TaskList) ->
    AllTasks = data_seven_goal:get_task_for_day(Day),
    DayTasks = [{Day, ModId, SubId} || {ModId, SubId} <- AllTasks],
    collect_task(DayList, DayTasks++TaskList).

%% 0点事件(特殊处理的任务：转职)；重新统计总进度
handle_event(Player, #event_callback{type_id = ?EVENT_ZERO_CLOCK}) ->
    #player_status{id = RoleId, seven_days_goal = SevenDaysGoal, figure = #figure{turn = Turn}} = Player,
    #seven_days_goal{
        open_time = OpenTime,
        days = Days,
        task_status = TaskStatus
    } = SevenDaysGoal,
    LoginDays = utime:day_span(OpenTime),
    MaxDay = ?ACT_OPEN_DAYS,
    if
        MaxDay =/= Days andalso LoginDays =/= Days andalso MaxDay >= LoginDays ->
            {NewTaskStatus, _AddScore} = update_data(RoleId, Turn, Days, LoginDays, TaskStatus),
            % {NewTaskStatus2, AddScore2} = special_task_init(Player, Days, LoginDays, NewTaskStatus, OtherData),
            NewScore = calc_all_finish_task(LoginDays, LoginDays, NewTaskStatus),
            SQL = io_lib:format(?SQL_UPDATE_LOGIN_DAY, [LoginDays, NewScore, RoleId]),
            db:execute(SQL),
            NewSevenDaysGoal = SevenDaysGoal#seven_days_goal{score = NewScore,days = LoginDays, task_status = NewTaskStatus},
            NewPlayer = Player#player_status{seven_days_goal = NewSevenDaysGoal},
            get_task_info(NewPlayer),
            {ok, NewPlayer};
        true -> {ok, Player}
    end;
%% 转职成功回调
handle_event(Player, #event_callback{type_id = ?EVENT_TURN_UP}) when is_record(Player, player_status) ->
    #player_status{figure = #figure{turn = Turn}} = Player,
    {ok, NewPlayer} = do_finish_task(Player, ?MOD_TRANSFORM, 1, Turn, true),
    {ok, NewPlayer};
%% 首充
handle_event(Player, #event_callback{type_id = ?EVENT_RECHARGE}) when is_record(Player, player_status) ->
    {ok, NewPlayer} = do_finish_task(Player, ?MOD_RECHARGE_ACT, 1, 1, true),
    {ok, NewPlayer};
handle_event(Player, _) ->
    {ok, Player}.

%% 特殊处理，这类任务在任务开启前就需要先计数完成次数（装备强化）暂时废弃
special_task_handle(Player, Type, Times) ->
    #player_status{seven_days_goal = SevenDaysGoal} = Player,
    #seven_days_goal{
        open_time = OpenTime,
        other_data = OtherData
    } = SevenDaysGoal,
    DiffDays = utime:day_span(OpenTime),
    if
         7 >= DiffDays ->
            case lists:keyfind(Type, 1, OtherData) of
                {_, FinTimes} ->
                    skip;
                _ ->
                    FinTimes = 0
            end,
            NOtherData = lists:keystore(Type, 1, OtherData, {Type, FinTimes + Times}),
            db:execute(io_lib:format(?SQL_UPDATE_OTHER_DATA,[util:term_to_bitstring(NOtherData), Player#player_status.id])),
            NSevenDaysGoal = SevenDaysGoal#seven_days_goal{other_data = NOtherData},
            NPlayer = Player#player_status{seven_days_goal = NSevenDaysGoal},
            {ok, NPlayer};
        true ->
            {ok, Player}
    end.
%% --------------------------------------------------------------------------------------------------------

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

check({is_open, OpenTime}) ->
    DiffDays = utime:day_span(OpenTime),
    if
        ?ACT_OPEN_DAYS >= DiffDays -> true;
        true -> {false, ?ERRCODE(err176_act_end)}
    end;
check({is_receive, Target, List}) ->
    case lists:member(Target, List) of
        true -> {false, ?ERRCODE(err331_already_get_reward)};
        false -> true
    end;
check({is_receive, LoginDays, ModId, SubId, TaskReward}) ->
    case lists:member({LoginDays, ModId, SubId}, TaskReward) of
        true -> {false, ?ERRCODE(err331_already_get_reward)};
        false -> true
    end;
check({is_enough, Score, TargetScore}) ->
    if
        Score >= TargetScore -> true;
        true -> {false, ?ERRCODE(err331_act_can_not_get)}
    end;
check({is_right_score_data, Score}) ->
    case data_seven_goal:get_score_cfg(Score) of
        #base_seven_goal_score{} -> true;
        _ -> {false, ?ERRCODE(missing_config)}
    end;
check({is_right_skill_data, Days}) ->
    case data_seven_goal:get_skill_reward_cfg(Days) of
        #base_seven_skill_reward{} -> true;
        _ -> {false, ?ERRCODE(missing_config)}
    end;
check({progress, LoginDays, ModId, SubId, TaskStatus}) ->
    case data_seven_goal:get_task_cfg(LoginDays, ModId, SubId) of
        #base_seven_goal_task{condition = Cond} ->
            case lists:keyfind(limit_times, 1, Cond) of
                {_, Times} ->
                    case lists:keyfind({LoginDays, ModId, SubId}, 1, TaskStatus) of
                        {_, Progress} when Progress >= Times ->
                            true;
                        _ ->
                            {false, ?ERRCODE(err331_act_can_not_get)}
                    end;
                _ -> {false, ?ERRCODE(missing_config)}
            end;
        _ -> {false, ?ERRCODE(missing_config)}
    end;
check({is_finish_all_task, Days, TaskStatus}) ->
    case data_seven_goal:get_task_for_day(Days) of
        [] -> {false, ?ERRCODE(missing_config)};
        TaskList ->
            F = fun({ModId, SubId}) ->
                case lists:keyfind({Days, ModId, SubId}, 1, TaskStatus) of
                    {_, FinishTimes} ->
                        case data_seven_goal:get_task_cfg(Days, ModId, SubId) of
                            #base_seven_goal_task{condition = Cond} ->
                                case lists:keyfind(limit_times, 1, Cond) of
                                    {_, CfgTimes} when FinishTimes >= CfgTimes ->
                                        true;
                                    _ ->
                                        false
                                end;
                            _ -> false
                        end;
                    _ -> false
                end
                end,
            case lists:all(F, TaskList) of
                true -> true;
                false -> {false, ?ERRCODE(err176_today_task_no_finish)}
            end
    end.

%% -----------------gm----------------------
gm_add_login_day(Player, AddDay) ->
    #player_status{id = RoleId, seven_days_goal = SevenDaysGoal} = Player,
    #seven_days_goal{
        open_time = OpenTime
    } = SevenDaysGoal,
    NewOpenTime = OpenTime - AddDay * 24 * 60 * 60,
    SQL = io_lib:format(?SQL_UPDATE_OPEN_TIME, [NewOpenTime, RoleId]),
    db:execute(SQL),
    NewPlayer = login_load_data(Player),
    get_task_info(NewPlayer),
    NewPlayer.
