/**
 * 体力系统
 */

import { ActionPointModel, ActionPointType } from '../db/ActionPoint';
import { TASK_TYPE, STATUS, TA_EVENT, ITEM_CHANGE_REASON, PUSH_ROUTE } from '../consts';
import { checkTask } from './task/taskService';
import { getDicApByLv } from '../pubUtils/data';
import { pinus } from 'pinus';
import { resResult, shouldRefresh } from '../pubUtils/util';
import { pick } from 'underscore';
import { AP } from '../pubUtils/dicParam';
import { reportTAEvent } from './sdkService';
import { sendMessageToUserWithSuc } from './pushService';

/**
 * 获取当前体力
 * @param roleId 玩家id
 * @param lv 玩家等级
 */
export async function getAp(roleId: string, ip: string, lv: number, fromGetAp = false) {
    let dataAp = await ActionPointModel.getAp(roleId);
    return getApWithDataAp(roleId, ip, lv, dataAp, fromGetAp);
}

function getApWithDataAp(roleId: string, ip: string, lv: number, dataAp: ActionPointType, fromGetAp = false) {

    const now = Date.now();
    const dicAp = getDicApByLv(lv);
    const maxAp = dicAp.maxAp; // 最大体力值
    const per = AP.PERAPRESTORETIME * 1000; // 恢复时间（ms)
    let { ap, refTime, buyRefTime = 0, buyTimes = 0, apBefore } = dataAp;
    let oldAp = ap;

    if(shouldRefresh(new Date(buyRefTime), new Date())) {
        buyTimes = 0;
    }

    let result;
    if (ap >= maxAp) {
        // 体力溢出不需要做时间的处理
        result = { ap, maxAp, refTime: now, apRemainTime: 0, apMaxRemainTime: 0, isOver: true, buyTimes, buyRefTime, apBefore };
    } else {
        if (refTime > now) refTime = now; // refTime：每次记录时候最近的一个整的时间点，绝对不会大于now
        let n = Math.floor((now - refTime) / per); // 上次记录到现在可以增长多少体力
        ap += n; // 增加上
        if (ap >= maxAp) { // 加上后溢出了
            ap = maxAp;
            result = { ap, maxAp, refTime: now, apRemainTime: 0, apMaxRemainTime: 0, isOver: true, buyTimes, buyRefTime, apBefore };
        } else {
            refTime += n * per; // 更新refTime到离现在最近的一个整的时间点
            let apRemainTime = Math.floor((refTime + per - now) / 1000); // 恢复下一点需要多少时间
            let apMaxRemainTime = (maxAp - ap - 1) * AP.PERAPRESTORETIME + apRemainTime;
            result = { ap, maxAp, refTime, apRemainTime, apMaxRemainTime, isOver: false, buyTimes, buyRefTime, apBefore };
        }
    }
    // if(result.ap > oldAp) {
    //     reportTAEvent(roleId, TA_EVENT.AP_GET, { change_count: result.ap - oldAp, change_after: result.ap, change_reason: ITEM_CHANGE_REASON.AP_RECOVERY })
    // }

    return fromGetAp?result: pick(result, ['ap', 'maxAp', 'apRemainTime', 'apMaxRemainTime', 'buyTimes', 'apBefore']);
}

/**
 * 增加或减少体力
 * @param roleId 玩家id
 * @param lv 玩家等级
 * @param changeAp 体力变化，正是加，负是减
 * @param sid 
 */
export async function setAp(serverId: number, roleId: string, ip: string, lv: number, changeAp: number, sid: string, reason: ITEM_CHANGE_REASON) {
    // console.log('***** setAp', roleId, ip, lv, changeAp)
    const now = Date.now();

    let ApResult = await getAp(roleId, ip, lv, true);
    let { ap: apBefore, maxAp, refTime, apRemainTime, apMaxRemainTime, isOver, buyTimes } = ApResult; // 更新ap
    let ap = apBefore + changeAp;
    if (ap >= maxAp) { // 溢出
        refTime = now;
        apRemainTime = 0;
        apMaxRemainTime = 0;
    }
    if (ap < 0) return null // 体力不足
    let dataAp = await ActionPointModel.saveAp(roleId, ap, apBefore, refTime);

    if (isOver && ap < maxAp) { // 特殊处理，溢出之后做减少体力的操作时
        apRemainTime = AP.PERAPRESTORETIME;
        apMaxRemainTime = (maxAp - ap) * AP.PERAPRESTORETIME;
    }

    if (changeAp < 0) {
        await checkTask(serverId, roleId, sid, TASK_TYPE.BATTLE_COST_AP, { count: -changeAp });
        // reportTAEvent(roleId, TA_EVENT.AP_CONSUME, { change_count: -1 * changeAp, change_after: ap, change_reason: reason }, ip)
    } else if(changeAp > 0){
        reportTAEvent(roleId, TA_EVENT.AP_GET, { change_count: changeAp, change_after: ap, change_reason: reason }, ip)
    }
    let apJson = await getApWithDataAp(roleId, ip, lv, dataAp);

    if (changeAp != 0) {
        sendMessageToUserWithSuc(roleId, PUSH_ROUTE.AP_UPDATE, { apJson: { ...apJson, apBefore } }, sid);
    }

    return apJson
}

export async function setApBuyTimes(roleId: string, ip: string, lv: number, sid: string, incTimes: number) {
    if(incTimes <= 0) return false;

    let ApResult = await getAp(roleId, ip, lv, true);
    let { ap, maxAp, refTime, apRemainTime, apMaxRemainTime, buyTimes, buyRefTime } = ApResult; // 更新ap

    if(shouldRefresh(new Date(buyRefTime), new Date())) {
        buyTimes = 0;
        buyRefTime = new Date();
    }
    buyTimes += incTimes;
    await ActionPointModel.saveBuyTimes(roleId, buyTimes, buyRefTime);

    let apJson = { ap, maxAp, refTime, apMaxRemainTime, apRemainTime, buyTimes };
    if(incTimes != 0) {
        sendMessageToUserWithSuc(roleId, PUSH_ROUTE.AP_UPDATE, { apJson }, sid);
    }
    return apJson;
}