import { FrontendOrBackendSession, pinus } from 'pinus';
import EventRecord, { EventRecordModel } from '../db/EventRecord';
import { RoleModel } from '../db/Role';
import { genCode, getRandEelmWithWeight, resResult, getRandSingleEelm } from '../pubUtils/util';
import { EVENT_STATUS, EVENT_RECORD_STATUS, EVENT_TYPE, EVENT_RANDOM_TYPE_ONE_OPEN, EVENT_QUIZ_NUM, EVENT_ANSWER_STATUS, FUNCS_ID, PUSH_ROUTE } from '../consts';
import { EVENT_REFRESH_NUM } from '../consts';
import { STATUS } from '../consts/statusCode';
import { gameData } from '../pubUtils/data';
import { DicQuestion } from '../pubUtils/dictionary/DicQuestion';
import { sendMessageToUserWithSuc } from './pushService';
import { WarStar } from '../domain/dbGeneral';

/**
 * 从检查接口调用，检查是否有这么个战斗，顺便保存一下battleCode
 * 
 * @param roleId 
 * @param eventStatus
 * @param battleId 
 * @param battleCode 
 */
export async function checkEventBattle(roleId: string, eventStatus: number, battleId: number, battleCode: string) {
    let now = new Date();
    let refTime = eventStatus == EVENT_STATUS.OPEN? getEventTime(now): 0;

    let result = await EventRecordModel.setBattleCode(roleId, battleId, refTime, battleCode);
    if (!result) {
        if(refTime) {
            let preTime = getEventTime(new Date(refTime - 1));
            // console.log('preTime:', preTime);
            result = await EventRecordModel.setBattleCode(roleId, battleId, preTime, battleCode);
        }
    }
    if (!result) {
        return { status: -1, resResult: resResult(STATUS.EVENT_INFO_NOT_FOUND) };
    } else {
        return { status: 0, data: result };
    }
}

/**
 * 从关卡结算接口调用，保存战斗情况
 * 
 * @param session 
 * @param roleId 
 * @param battleId 
 * @param isSuccess 
 * @param battleCode 
 */
export async function setBattleStatus(session: FrontendOrBackendSession, roleId: string, battleId: number , isSuccess: boolean, battleCode: string) {

    let { BATTLE_SUCCESS, BATTLE_FAIL } = EVENT_RECORD_STATUS;
    let result = await EventRecordModel.setBattleStatus(roleId, battleId, battleCode, isSuccess?BATTLE_SUCCESS:BATTLE_FAIL);
    if (!result) {
        return { status: -1, resResult: resResult(STATUS.EVENT_INFO_NOT_FOUND) };
    } 
    // await checkEvent(session, true);
    return { status: 0, data: result };
}

/**
 * 获取刷新时间，12点时间或18点时间
 * 
 * @param now 
 */
export function getEventTime(now: Date) {
    let curTime = Number(now);
    let todayA = now.setHours(12, 0, 0, 0); // 每天12点
    let todayB = now.setHours(18, 0, 0, 0); // 每天18点
    let yesterdayB = todayB - 86400000; // 前一天12点
    let t = 0;
    if(curTime < todayA) {
        t = yesterdayB;
    } else if (curTime >= todayA && curTime < todayB) {
        t = todayA;
    } else if (curTime >= todayB) {
        t = todayB;
    }
    return t
}

/**
 * 从挑战结算接口调用，挑战完主线某一关，开始刷奇遇关卡
 * 
 * @param session 
 */
export async function startEvent(session: FrontendOrBackendSession) {

    const eventStatus = session.get('eventStatus');
    // console.log('*******startEvent ', eventStatus)
    if(eventStatus == EVENT_STATUS.WAITING) {
        let roleId = session.get('roleId');
        let roleName = session.get('roleName');
        let sid = session.get('sid');
        let event = await refreshEvent(1, roleId, roleName, 0, []); // 刷新初始的一件
        if(event.length > 0) {
            await RoleModel.setEventStatus(roleId, EVENT_STATUS.STARTING);
            session.set('eventStatus', EVENT_STATUS.STARTING);
            session.push('eventStatus', () => {});
            pushEventMsg(sid, roleId, { event }); // 推送
        }
        return event;
    } else {
        return []
    }
}

/**
 * 获取当前的奇遇事件
 * 
 * @param eventStatus 
 * @param roleId 
 * @param roleName 
 */
export async function getEvent(eventStatus: number, roleId: string, roleName: string) {
    
    let now = new Date();
    let curTime = getEventTime(now); // 这次的时间节点 0-12：前一天的18 12-18：12 18-24： 18
    let preTime = getEventTime(new Date(curTime - 1));    // 上一次的时间节点 

    let event: Array<EventRecord> = [];
    if (eventStatus == EVENT_STATUS.STARTING) {
        let result = await EventRecordModel.getEventRecordByTime(roleId, 0);
        for(let e of result) event.push(e);
    } else if( eventStatus == EVENT_STATUS.OPEN ) {
        let preEvents = await EventRecordModel.getEventRecordByTime(roleId, preTime); // 上次3个
        if(!preEvents.length) preEvents = await EventRecordModel.getEventRecordByTime(roleId, 0); 
        let curEvents = await EventRecordModel.getEventRecordByTime(roleId, curTime); // 这次3个

        if(curEvents.length == 0) { // 这次3个没刷过，那就刷一下
            let result = await refreshEvent(EVENT_REFRESH_NUM, roleId, roleName, curTime, preEvents);
            for(let e of result) event.push(e);
        } else {
            for(let e of curEvents) event.push(e);
        }

        for(let e of preEvents) {
            let index = event.findIndex(cur => cur.point == e.point);
            if(index == -1) { // 这个位置空着，则塞入
                event.push(e);
            } else {
                let curEvent = event[index];
                if(curEvent.status == EVENT_RECORD_STATUS.FAIL_RECEIVED || curEvent.status == EVENT_RECORD_STATUS.SUCCESS_RECEIVED) { // 当前的几个已领取，pre的补位
                    event[index] = e;
                }
            }
        }
    }

    return event;
}


/**
 * 刷新事件
 * 
 * @param num 刷多少事件
 * @param roleId 
 * @param roleName 
 * @param t 时间刷新时间，每天的12点或18点
 */
export async function refreshEvent(num: number, roleId: string, roleName: string, t: number, preEvents: Array<any>) {
    let {WAITING, BATTLE_SUCCESS, BATTLE_FAIL} = EVENT_RECORD_STATUS;

    let prePoint = preEvents.filter(cur => {
        return [WAITING, BATTLE_SUCCESS, BATTLE_FAIL].includes(cur.status); 
    }).map(cur => cur.point);

    let event = new Array();
    let dicEvent = gameData.eventList.filter(cur => cur.movePointArray && cur.movePointArray.length > 0);
    let role = await RoleModel.findByRoleId(roleId);
    dicEvent = dicEvent.filter(cur => { // 筛选适合等级
        let { suitLevel, previousGk } = cur;
        return suitLevel.min <= role.lv && suitLevel.max >= role.lv && checkPreviousGk(previousGk, role.warStar)
    });
    if(EVENT_RANDOM_TYPE_ONE_OPEN) {
        let historyRecord = await EventRecordModel.getHostoryEventRecord(roleId);
        let {history, turn} = historyRecord;
        let randomList = dicEvent.filter(cur => {
            return history.find(ccur => {
                return ccur.eventId != cur.eventID;
            });
        });
    
        let curPoint = new Array<number>();
        for(let i = 0; i < num; i++) {
            if(randomList.length == 0) { // 一轮刷新过，开始新的一轮，保证所有事件都能刷新一遍
                turn ++;
                randomList = [...dicEvent];
            }
            if(randomList.length == 0) break; // 如果还是为0，pass
    
            let index = Math.floor(Math.random() * randomList.length);
            let dic = randomList[index];
            let point = randomPosition(dic.movePointArray, prePoint, curPoint);
            if(!point) break;
            let question = dic.eventType == EVENT_TYPE.QUIZ?randomQuestion(EVENT_QUIZ_NUM): undefined;
            let eventCode = genCode(8);
            let data = await EventRecordModel.saveEventRecord(eventCode, {
                roleId, refTime: t, eventId: dic.eventID,
                roleName, turn, type: dic.eventType, battleId: dic.warId||0, quality: dic.quality,
                status: EVENT_RECORD_STATUS.WAITING,
                point, question
            });
            event.push(data);
            randomList.splice(index, 1);
        }
    } else {
        let randomList = dicEvent;
        if(randomList.length == 0) return []
        let curPoint = new Array<number>();
        for(let i = 0; i < num; i++) {
            let {dic} = getRandEelmWithWeight(randomList);
            // 临时处理，不出现相同的关卡id
            for(let x = 0; x < 1000; x++) { // 防死循环
                let hasEvent = event.find(cur => {
                    return cur.type == EVENT_TYPE.BATTLE && cur.battleId == dic.warId});
                let hasPreEvent = preEvents.find(cur => {
                    return cur.type == EVENT_TYPE.BATTLE && cur.battleId == dic.warId});

                if(x < 500) { // 基本不希望本轮和上轮出现过的关卡再次出现
                    if(!hasEvent && !hasPreEvent) break;
                } else { // 但是实在找不到，只要本轮没出现过就好
                    if(!hasEvent) break;
                }
                dic = getRandEelmWithWeight(randomList).dic;
            }

            if(!dic) break;
            let point = randomPosition(dic.movePointArray, prePoint, curPoint);
            if(!point) break;
            let eventCode = genCode(8);
            let question = dic.eventType == EVENT_TYPE.QUIZ?randomQuestion(EVENT_QUIZ_NUM): [];
            let data = await EventRecordModel.saveEventRecord(eventCode, {
                roleId, refTime: t, eventId: dic.eventID,
                roleName, type: dic.eventType, battleId: dic.warId||0, quality: dic.quality,
                status: EVENT_RECORD_STATUS.WAITING,
                point, question
            });
            event.push(data)
        }

    }
    return event;
}

export function checkPreviousGk(previousGk: number, warStar: WarStar[]) {
    if(!previousGk) return true;
    let preBattle = warStar.findIndex(cur => cur.id == previousGk);
    return preBattle != -1;
}

/**
 * 随机出当前事件的位置
 * 
 * @param positionStr 
 */
export function randomPosition(positionArr: number[], prePoint: Array<number>, curPoint: Array<number>) {
    let range = positionArr.filter(point => {return !prePoint.includes(point) && !curPoint.includes(point)});
    if(range.length == 0) { // 如果位置总数不够，就不管prePoint里的
        range = positionArr.filter(point => {return !curPoint.includes(point)});
    }
    if(range.length == 0) { // 还是不够，那是配表的问题，直接报错
        return false;
    }
    let index = Math.floor(Math.random() * range.length);
    let point = range[index];
    curPoint.push(point);

    return point
}

/**
 * 推送
 * 
 * @param roleId 
 * @param msg 
 */
function pushEventMsg(sid: string, roleId: string, msg: any ) {
    sendMessageToUserWithSuc(roleId, PUSH_ROUTE.SEND_EVENT, msg, sid);
}

/**
 * 领取奖励时检查状态是否正确
 * 
 * @param type 事件类型
 * @param status 状态id
 */
export function checkEventStatus(type: number, status: number) {
    // console.log('type = '+ type + ' status = '+status);
    let flag: boolean; // 检查状态是否正确
    if(type == EVENT_TYPE.BATTLE||type ==EVENT_TYPE.QUIZ) {
        if(status == EVENT_RECORD_STATUS.BATTLE_SUCCESS) {
            flag = true;
        } else if (status == EVENT_RECORD_STATUS.BATTLE_FAIL) {
            flag = true;
        } else {
            flag = true;
        }
    } else {     
       if(status == EVENT_RECORD_STATUS.WAITING) {
            flag = true;
       } else {
            flag = false;
       }
    } 
    return flag
}

/**
 * 领取奖励时调用，领取的是胜利奖励还是失败奖励
 * 
 * @param type 
 * @param status 
 * @param question 
 */
export function getEventSuccessStatus(type: number, status: number, question: Array<{id: number, status: number}>) {
    let isSuccess: boolean, returnResult = 1; // 检查状态是否正确
    if(type == EVENT_TYPE.BATTLE) {
        if(status == EVENT_RECORD_STATUS.BATTLE_SUCCESS) {
            isSuccess = true;
        } else {
            isSuccess = false;
        }
    } else if(type == EVENT_TYPE.BOX) {     
        isSuccess = true;
    } else if (type == EVENT_TYPE.QUIZ) {
        isSuccess = true;
        for(let { status = EVENT_ANSWER_STATUS.WAITING } of question) {
            // console.log(status);
            if(status == EVENT_ANSWER_STATUS.WRONG) {
                isSuccess = false;
            } else if(status == EVENT_ANSWER_STATUS.WAITING) {
                isSuccess = false;
                returnResult = -1;
            }
        }
    }
    return { isSuccess, status: returnResult }
}

export function checkQuizParam(param: Array<number>, database?:  Array<{id: number}>) {

    if(database) {
        let flag = true;
        for(let {id} of database) {
            let index = param.indexOf(id);
            if(index == -1) flag = false; break;
        }
        return flag
    } else {
        return true
    }
}

/**
 * 从题库中随机题目
 * 
 * @param num 题目数量
 */
export function randomQuestion(num: number) {
    let questions = new Array<DicQuestion>();
    gameData.question.forEach(cur => {
        questions.push(cur);
    });
    let rid:Array<number> = [], result = [];
    while(num > 0) {
        let dicQuestion = getRandSingleEelm(questions);
        let {id, question, answer } = dicQuestion;
        if(rid.includes(id)) continue;
        rid.push(id);
        result.push({id, question, answer});
        num--;
    }
    return result;
}

/**
 * 对答案
 * 
 * @param id 
 * @param answer 
 */
export function checkQuiz(id: number, answer: number) {
    let result = gameData.question.get(id);

    return {
        isCorrect: !!result && result.correct == answer,
        answerNo: result?result.correct: 0
    }
}

