import { MarqueeType, MarqueeModel } from "../db/Marquee";
import { ACTIVITY_TYPE, MARQUEE_SHOW_TYPE, MARQUEE_TIME_TYPE, REDIS_KEY, SURVEY_SELECT } from "../consts";
import { scheduleJob, scheduledJobs, Job } from 'node-schedule';
import { createMarqueeMsg as sysCreateMarqueeMsg, pushMarqueeMsg as sysPushMarqueeMsg } from './sysChatService';
import { GroupMessageType } from "../db/GroupMessage";
import { pinus } from "pinus";
import { ServerlistModel, ServerlistType } from "../db/Serverlist";
import { sendMailsByGmMail } from "./mailService";
import GMMail, { GMMailModel } from '../db/GMMail';
import { getPastTime, nowSeconds } from "../pubUtils/timeUtil";
import { CreateServerParam } from "../domain/backEndField/params";
import { SignInData } from "../domain/activityField/signInField";
import { RegionModel, RegionType } from "../db/Region";
import { GMMail as StategyMail } from "../db/ServerStategy";
import { uniq } from "underscore";
import { ActivityModel, ActivityModelType } from "../db/Activity";
import { dicRMB } from "../pubUtils/dictionary/DicRMB";
import { LimitShopData } from "../domain/activityField/limitShopField";
import { YuanBaoShopData } from "../domain/activityField/yuanBaoShopField";
import { MonthlyTicketData } from "../domain/activityField/monthlyTicketField";
import { DailyRMBGiftsData } from "../domain/activityField/dailyRMBGiftsField";
import { PopShopItem, PopUpShopData, PopUpShopPackage } from "../domain/activityField/popUpShopField";
import { GrowthFundData } from "../domain/activityField/growthFundField";
import { TreasureHuntData } from "../domain/activityField/treasureHuntField";
import { RefreshShopData } from "../domain/activityField/refreshShopField";
import { RoleType } from "../db/Role";
import { MonopolyData } from "../domain/activityField/monopolyField";
import { ActivityPopUpShopModel, PopUpShopItem } from "../db/ActivityPopUpShop";
import { getActivitiesByType } from "./activity/activityService";
import { SurveyModel } from "../db/Survery";
import { SurveyRecModel } from "../db/SurveyRec";
import { getPopUpShopData } from "./activity/popUpShopService";
import { TaskPassData } from "../domain/activityField/taskPassField";
import { ActivityGroupModel } from "../db/ActivityGroup";
import { redisClient } from "./redisService";
import { gameData } from "../pubUtils/data";
import { GuildModel } from "../db/Guild";
import { GuildTrainModel } from "../db/GuildTrain";
import { unlockTrain } from "./guildTrainService";
import { HiddenDataModel, HiddenDataModelType } from "../db/HiddenData";
import { HiddenDataByIdModel } from "../db/HiddenDataById";
import moment = require("moment");

// —————————————— 跑马灯 —————————————— //
// 初始
export async function initMarquee() {
    const marquees = await MarqueeModel.findEffectiveMarque(pinus.app.get('env'));
    for(let marquee of marquees) {
        await generateMarqueeSchedule(marquee);
    }
}

export async function setMarquee(marquee: MarqueeType) {
    console.log('******', marquee.timeType, marquee)
    if(marquee.timeType == MARQUEE_TIME_TYPE.INSTANT) {
        await startMarquee(marquee);
        return true;
    } else {
        return await generateMarqueeSchedule(marquee);
    }
}

async function generateMarqueeSchedule(marquee: MarqueeType) {
    // 定时发送
    let setSecondsMarquee = scheduledJobs[`setSeconds${marquee.code}`];
    if(setSecondsMarquee) return false; // 已经在运行中了

    if(marquee.timeType != MARQUEE_TIME_TYPE.SCHEDULE) return false;
    if(marquee.endTime && marquee.endTime < nowSeconds()) return false;
    let startJob = scheduleJob(`start${marquee.code}`, marquee.startTime * 1000, async () => {
        await startMarquee(marquee, startJob)
    });
    return true;
}

async function startMarquee(marquee: MarqueeType, startJob?: Job) {
    console.log('************', `跑马灯定时器 ${marquee.code}开始`, '************');
    let msgDatas = await createMarqueeMsg(marquee);
    if(marquee.showType == MARQUEE_SHOW_TYPE.ONCE) { // 一次性发送
        await pushMarqueeMsg(msgDatas);
        if(startJob) {
            startJob.cancel();
            startJob = undefined;
        }
    } else {
        if(marquee.endTime > nowSeconds()) {
            await pushMarqueeMsg(msgDatas);
            let secondsJob = scheduleJob(`setSeconds${marquee.code}`, `*/${marquee.interval} * * * * *`, async () => {
                console.log(`*****setSeconds${marquee.code}****`)
                await pushMarqueeMsg(msgDatas);
            });
            let endJob = scheduleJob(`end${marquee.code}`, marquee.endTime * 1000, async () => {
                if(startJob) {
                    startJob.cancel();
                    startJob = undefined;
                }
                if(secondsJob) {
                    secondsJob.cancel();
                    secondsJob = undefined;
                }
                if(endJob) {
                    endJob.cancel();
                    endJob = undefined;
                }
            });
        } else {
            if(startJob) {
                startJob.cancel();
                startJob = undefined;
            }
        }
    }
}

async function createMarqueeMsg(marquee: MarqueeType) {
    let { receivers, content } = marquee;
    let msgDatas: GroupMessageType[] = [];
    let serverIds: number[] = [];
    for(let { env, serverId } of receivers) {
        if(serverId == 0) {
            let servers = await ServerlistModel.findByEnv(env);
            for(let { id } of servers) {
                serverIds.push(id);
            }
        } else {
            serverIds.push(serverId);
        }
    }
    for(let serverId of uniq(serverIds)) {
        let msgData = await sysCreateMarqueeMsg('', '系统', serverId, content);
        msgDatas.push(msgData);
    }

    return msgDatas;
}

async function pushMarqueeMsg(msgDatas: GroupMessageType[]) {
    for(let msgData of msgDatas) {
        await sysPushMarqueeMsg(msgData);
    }
}

export async function cancelMarquee(code: string) {
    let startMarquee = scheduledJobs[`start${code}`];
    let setSecondsMarquee = scheduledJobs[`setSeconds${code}`];
    let endMarquee = scheduledJobs[`end${code}`];
    if(startMarquee) startMarquee.cancel();
    if(setSecondsMarquee) setSecondsMarquee.cancel();
    if(endMarquee) endMarquee.cancel();
    return true
}

export async function sendOpenServerMail(type: 'openMail'|'circleMail', mail: StategyMail, newServer: ServerlistType, uid: number) {
     let addParam = new GMMail();
     addParam.setByRegionStategy(type, mail, newServer, uid);
    let gmmail = await GMMailModel.addMail(addParam, uid);

    await sendMailsByGmMail([gmmail]);
    return true;
}

export function setServerMainten(serverIds: number[], startTime: number, endTime: number) {
    let maintenServers = pinus.app.get('maintenServers')||new Map();
    for(let id of serverIds) {
        if(!maintenServers.has(id)) {
            maintenServers.set(id, { startTime, endTime });
        } else {
            maintenServers.get(id).startTime = startTime;
            maintenServers.get(id).endTime = endTime;
        }
    }
    pinus.app.set('maintenServers', maintenServers);
}


export function stopServerMainten(serverIds: number[]) {
    let maintenServers = pinus.app.get('maintenServers')||new Map();
    for(let id of serverIds) {
        if(maintenServers.has(id)) {
            maintenServers.delete(id);
        }
    }
    pinus.app.set('maintenServers', maintenServers);
}

export function getServerMainten(serverId: number) {
    let maintenServers = pinus.app.get('maintenServers')||new Map();
    return maintenServers.get(serverId);
}

export async function createNewServer(region: RegionType ,serverId: number, params: CreateServerParam, uid?: number) {
    let newServer = await ServerlistModel.newServer(params, region, serverId, uid);
    if(params.openMail) await sendOpenServerMail('openMail', params.openMail, newServer, uid);
    if(params.circleMail) await sendOpenServerMail('circleMail', params.circleMail, newServer, uid);
    if(params.activityGroupId && params.activityGroupId.length > 0) {
        await ActivityGroupModel.addServerToGroupData(newServer.id, params.activityGroupId);
        let activityGroups = await ActivityGroupModel.findByServerId(newServer.id);
        await pinus.app.rpc.activity.activityRemote.addServerToGroup.broadcast(params.activityGroupId, [newServer.id]);

        let aids = activityGroups.reduce((pre, cur) => [...pre, ...cur.activities], []);
        let activities = await ActivityModel.findActivityByIds(aids);
        let timeLimitRanks = activities.filter(cur => cur.type == ACTIVITY_TYPE.TIME_LIMIT_RANK);
        if(timeLimitRanks.length > 0) {
            pinus.app.rpc.systimer.systimerRemote.updateTimeLimitRank.broadcast(timeLimitRanks);
        }
    }
    await RegionModel.newServer(region.id, newServer);
    await redisClient().hsetAsync(REDIS_KEY.SERVER, `${newServer.id}`, `${newServer.name}`);
    await redisClient().hsetAsync(REDIS_KEY.SERVER_OPEN_TIME, `${newServer.id}`, `${newServer.openTime}`);

}

function getDicRMB(productID: string) {
    let dic = dicRMB.get(productID);
    if(!dic) return null
    return {
        value: dic.productID,
        label: `${dic.message}(${dic.productID})`,
    }
};

export function getActivityProducts(activity: ActivityModelType) {
    switch(activity.type) {
        case ACTIVITY_TYPE.SIGN_IN_VIP: // 高级签到
        {
            let data = new SignInData(activity, 0, 0);
            return [getDicRMB(data.productID)];
        }
        case ACTIVITY_TYPE.NEW_PLAYER_LIMIT_PACKAGE: // 新手限定RMB购买礼包
        case ACTIVITY_TYPE.LIMIT_PACKAGE_SHOP_DAILY: // 日限购
        case ACTIVITY_TYPE.LIMIT_PACKAGE_SHOP_WEEKLY: // 周限购
        {
            let data = new LimitShopData(activity, 0, 0);
            return data.list.map(item => {
                return getDicRMB(item.productID);
            });
        }
        case ACTIVITY_TYPE.YUAN_BAO_SHOP: // 元宝
        {
            let data = new YuanBaoShopData(activity, 0, 0);
            return data.list.map(item => {
                return getDicRMB(item.productID);
            });
        }
        case ACTIVITY_TYPE.MONTHLY_TICKET_1:
        case ACTIVITY_TYPE.MONTHLY_TICKET_2:
        {
            let data = new MonthlyTicketData(activity, 0, 0);
            return [getDicRMB(data.productID)];
        }
        case ACTIVITY_TYPE.DAILY_RMB_GIFTS:
        {
            let data = new DailyRMBGiftsData(activity, 0, 0);
            return [getDicRMB(data.productID)];
        }
        case ACTIVITY_TYPE.POP_UP_SHOP://弹出礼包
        {
            let products: { label: string, value: string }[] = [];
            let data = new PopUpShopData(activity);
            for(let { items } of data.packages) {
                for(let item of items) {
                    products.push(getDicRMB(item.productID));
                }
            }
            return products;
        }
        case ACTIVITY_TYPE.GROWTH_FUND_MAIN_VIP: //主线成长基金（高阶）
        case ACTIVITY_TYPE.GROWTH_FUND_TOWER_VIP://镇念塔成长基金（高阶）
        case ACTIVITY_TYPE.GROWTH_FUND_MAIN_ELITE_VIP://精英成长基金（高阶）
        {
            let data = new GrowthFundData(activity, 0, 0);
            return data.list.map(item => {
                return getDicRMB(item.productID);
            });
        }
        case ACTIVITY_TYPE.TREASURE_HUNT:
        {
            let data = new TreasureHuntData(activity, 0, 0);
            let shop = data.shop;
            return shop.list.map(item => {
                return getDicRMB(item.productID);
            });
        }
        case ACTIVITY_TYPE.REFRESH_SHOP:
        {
            let data = new RefreshShopData(activity, 0, 0);
            let products: { label: string, value: string }[] = [];
            for(let shop of data.list) {
                for(let item of shop.items) {
                    products.push(getDicRMB(item.productID));
                }
            }
            return products;
        }
        case ACTIVITY_TYPE.TASK_PASS:
        {
            let data = new TaskPassData(activity, 0, 0);
            let products: { label: string, value: string }[] = [];
            for(let reward of data.rewards) {
                products.push(getDicRMB(reward.productID));
            }
            return products;
        }

    }
    return false
}

export async function getParamStr(activity: ActivityModelType, productID: string, role: RoleType) {
    let param = {};
    switch(activity.type) {
        case ACTIVITY_TYPE.POP_UP_SHOP:
            const roleId = role.roleId;
            let serverId = role.serverId;
            let playerData = await getPopUpShopData(activity.activityId, serverId, roleId, role);
            let item: PopShopItem, pkg: PopUpShopPackage;
            for(let _pkg of playerData.packages) {
                let _item = _pkg.findItemByProductID(productID);
                if(_item) {
                    pkg = _pkg; item = _item;
                }
            }
            if(item.isPushing) {
                param['code'] = item.code;
            } else {
                let popUpShopRec = await ActivityPopUpShopModel.createRecord({ 
                    serverId, activityId: activity.activityId, roleId, id: pkg.id, 
                    ...await pkg.getEffectTime(),
                    items: pkg.items.map(item => new PopUpShopItem(item))
                });
                param['code'] = popUpShopRec.code;
            }


            // let playerRecords = await ActivityPopUpShopModel.findAllOpenData(role.serverId, activity.activityId, role.roleId);
            // let playerRecord: ActivityPopUpShopModelType;
            // for(let record of playerRecords) {
            //     let playerData = new PopUpShopData(task, activity.activityId);
            //     playerData.setPlayerRecords(record);
            //     if (record && playerData.buyCount < task.count) {
            //         playerRecord = record; break;
            //     }
            // }
            // console.log('####', playerRecord, task)
            // if(!playerRecord) {
            //     let beginTime = new Date();
            //     let endTime = moment(new Date()).add(task.duration, 'h').toDate();
            //     playerRecord = await ActivityPopUpShopModel.addTaskPushMessage(role.serverId, activity.activityId, role.roleId, task.id, task.taskType, task.condition, beginTime, endTime);    
            // }

            // param['beginTimeStamp'] = playerRecord.beginTime.getTime();
            break;
        case ACTIVITY_TYPE.REFRESH_SHOP:
            let monopolyActivitys = await getActivitiesByType(role.serverId, ACTIVITY_TYPE.MONOPOLY);
            let parentActivity = monopolyActivitys.find(activity => {
                let data = new MonopolyData(activity, 0, 0);
                let curShop = data.list.find(land => { // 找到关联活动
                    return land.shopActivityId == activity.activityId;
                });
                return !!curShop;
            });

            if(parentActivity) {
                param['monopolyActivityId'] = parentActivity.activityId;
            }
            break;
    }
    return JSON.stringify(param);
}


export async function getSurvey(roleId: string, lv: number) {
    let surveys = await SurveyModel.findEnableSurvey(lv, SURVEY_SELECT.FIND);
    let recs = await SurveyRecModel.findByRole(roleId);
    return surveys.filter(survey => {
        let index = recs.findIndex(rec => rec.surveyId == survey.surveyId);
       return index == -1
    });
}

export async function setTrainLv(guildCode: string, trainLv: string) {
    let [_lv, _id] = trainLv.split('-');
    let lv = parseInt(_lv), id = parseInt(_id);
    if(!isNaN(lv) && !isNaN(id)) {
        let structure = gameData.trainBase.get(lv);
        let trainIds = structure?.trainIds||[];
        let trainId = trainIds[id - 1];
        if(trainId) {
            await GuildModel.updateInfo(guildCode, { trainId, trainLv: lv });
            await GuildTrainModel.resetGuildTrain(guildCode);
            await unlockTrain(guildCode, trainId);
        }
    }
}

export async function calHiddenData(uid: number) {
    let result = await HiddenDataByIdModel.findAllData();
    console.log('####', JSON.stringify(result))
    let heroes: number[] = [], goods: number[] = [];
    await HiddenDataModel.clearData();
    for(let { _id, ids } of result) {
        await HiddenDataModel.updateHiddenData(_id, heroes, goods, uid);
        for(let {type, id} of ids) {
            if(type == 1) heroes.push(id);
            if(type == 2) goods.push(id);
        }
    }
    await HiddenDataModel.updateHiddenData(getPastTime(), heroes, goods, uid);
}