import { Service } from 'egg';
import { STATUS, ACTIVITY_TYPE } from '@consts';
import { ActivityModel } from '@db/Activity';
import { ActivityGroupModel } from '@db/ActivityGroup';
import { ServerlistModel } from '@db/Serverlist';
import { GMUserType } from '@db/GMUser';
import { SignInData } from '@domain/activityField/signInField';
import { ActivityGroupTypeModel } from '@db/ActivityGroupType';
import { ActivityTaskPointModel } from '@db/ActivityTaskPoint'; 
import { gameData } from '@pubUtils/data';

/**
 * Test Service
 */
export default class Activity extends Service {

    /**
     * 获得活动列表
     */
    public async getActivityList(page: number, pageSize: number, sortField: string, sortOrder: string, type: number = 0, groupId: number = 0, current: boolean = false, activityId: number = 0) {
        const { ctx } = this;
        // console.log('***', page, pageSize, type, groupId, current, activityId)
        const list = await ActivityModel.findByCondition(page, pageSize, sortField, sortOrder, type, groupId, current, activityId);
        const total = await ActivityModel.countByCondition(type, groupId, current, activityId);
        return ctx.service.utils.resResult(STATUS.SUCCESS, {
            list: list.map(cur => {
                return {
                    ...cur, beginTime: cur.beginTime.getTime(), endTime: cur.endTime.getTime()
                }
            }), total
        });
    }

    public async checkActivityEditable(activityId: number) {
        let now = new Date();
        let activity = await ActivityModel.findActivity(activityId);

        if(this.app.config.env == 'production') {
            if(!activity || (activity.beginTime < now && activity.endTime > now)) {

                if(activity.type == ACTIVITY_TYPE.SIGN_IN || activity.type == ACTIVITY_TYPE.SIGN_IN_VIP) {
                    // 签到活动的不显示期内也可以编辑
                    let signInObj = new SignInData(activity, 0);
                    if(signInObj.beginTime < now.getTime() && signInObj.endTime > now.getTime() ) {
                        return this.ctx.service.utils.resResult(STATUS.GM_CAN_NOT_EDIT_ACT);
                    }
                } else {
                    return this.ctx.service.utils.resResult(STATUS.GM_CAN_NOT_EDIT_ACT);
                }
            }
        }
        return 0
    }

    private async checkActivityGroupType(groupId: number, aids: number[], ctx) {

        let activityGroup = await ActivityGroupModel.findGroupData(groupId);
        if(!activityGroup) return ctx.service.utils.resResult(STATUS.GM_ACTIVITY_GROUP_NOT_FOUND);
        if(activityGroup.type != 0) {
            let activityGroupType = await ActivityGroupTypeModel.findByGroupType(activityGroup.type);
            if(!activityGroupType) return ctx.service.utils.resResult(STATUS.GM_ACTIVITY_GROUP_TYPE_NOT_FOUND);
            let dic = activityGroupType.activityTypes;
            let activities = await ActivityModel.findActivityByIds(aids);
            for(let { type } of activities) {
                let index = dic.findIndex(cur => cur.activityType == type);
                if(index == -1) {
                    return ctx.service.utils.resResult(STATUS.GM_ACTIVITY_NOT_FIT_GROUP_TYPE);
                } else {
                    dic.splice(index, 1);
                }
            }
        }

        return 0
    }

    public async updateActivity(activityId: number | string, groupId: number, beginTime: number, endTime: number, type: number, data: string) {
        const { ctx } = this;
        let gmuser: GMUserType = ctx.user;
        if (!type || !data) {
            return ctx.service.utils.resResult(STATUS.WRONG_PARMS);
        }
        try {
            let result = JSON.parse(data);
            ctx.service.utils.checkActivityData(result, type);
            let aids: number[] = [];
            if (typeof activityId == 'number') {
                aids.push(activityId);
            } else {
                activityId.split(',').forEach(aidStr => {
                    aids.push(parseInt(aidStr));
                });
            }
            
            let checkResult = await this.checkActivityGroupType(groupId, aids, ctx);
            if(checkResult) return checkResult;

            let activities = await ActivityModel.addActivity(aids, groupId, beginTime ? new Date(beginTime) : undefined, endTime ? new Date(endTime) : undefined, type, data, gmuser.uid);
            return ctx.service.utils.resResult(STATUS.SUCCESS, {
                activity: activities
            })

        } catch (e) {
            return ctx.service.utils.resResult(STATUS.INTERNAL_ERR, null, e.stack);
        }
    }
    
    public async deleteActivity(activityId: number) {
        const { ctx } = this;
        const result = await ActivityModel.deleteActivity(activityId, ctx.user?.uid);
        if (result) {
            return ctx.service.utils.resResult(STATUS.SUCCESS);
        } else {
            return ctx.service.utils.resResult(STATUS.ACTIVITY_MISSING);
        }
    }

    /**
     * 获得活动组列表
     */
    public async getActivityGroupList(page: number, pageSize: number, serverId: number = 0, current: boolean = false, groupId: number = 0) {
        const { ctx } = this;
        // console.log('***', page, pageSize, type, serverId, current, activityId)
        const list = await ActivityGroupModel.findByCondition(page, pageSize, serverId, current, groupId);
        const total = await ActivityGroupModel.countByCondition(serverId, current, groupId);
        return ctx.service.utils.resResult(STATUS.SUCCESS, {
            list: list.map(cur => {
                return {
                    ...cur, beginTime: cur.beginTime?.getTime(), endTime: cur.endTime?.getTime()
                }
            }), total
        });
    }

    /**
     * 更新活动组
     */
    public async updateActivityGroupName(groupId: number, groupName: string) {
        const { ctx } = this;
        try {
            await ActivityGroupModel.updateGroup(groupId, {groupName}, ctx.user?.uid);
        } catch(e) {
            return ctx.service.utils.resResult(STATUS.INTERNAL_ERR, null, e.stack);
        }
        return ctx.service.utils.resResult(STATUS.SUCCESS)
    }

    /**
     * 选择活动组内的活动
     */
    public async saveActivitiesToGroup(groupId: number, activityIds: number[]) {
        const { ctx } = this;
        try {
            let checkResult = await this.checkActivityGroupType(groupId, activityIds, ctx);
            if(checkResult) return checkResult;

            await ActivityGroupModel.setActivitiesToGroupData(groupId, activityIds, ctx.user?.uid);
    
        } catch(e) {
            return ctx.service.utils.resResult(STATUS.INTERNAL_ERR, null, e.stack);
        }
        return ctx.service.utils.resResult(STATUS.SUCCESS)
    }

    /**
     * 选择活动组内的活动
     */
    public async saveSingleActivityToGroup(groupId: number, index: number, activityId: number) {
        console.log(groupId, index, activityId);
        const { ctx } = this;
        try {
            let checkResult = await this.checkActivityGroupType(groupId, [activityId], ctx);
            if(checkResult) return checkResult;

            let activityGroup = await ActivityGroupModel.findGroupData(groupId);
            if(!activityGroup) return ctx.service.utils.resResult(STATUS.GM_ACTIVITY_GROUP_NOT_FOUND);
            let activity = await ActivityModel.findActivity(activityId);
            if(!activity) return ctx.service.utils.resResult(STATUS.ACTIVITY_MISSING);

            if(activityGroup.type != 0) {
                let activityGroupType = await ActivityGroupTypeModel.findByGroupType(activityGroup.type);
                if(!activityGroupType) return ctx.service.utils.resResult(STATUS.GM_ACTIVITY_GROUP_TYPE_NOT_FOUND);
                let dic = activityGroupType.activityTypes;
                let curDic = dic.find(cur => cur.index == index);
                console.log(dic, curDic)
                if(curDic.activityType != activity.type) return ctx.service.utils.resResult(STATUS.GM_ACTIVITY_NOT_FIT_GROUP_TYPE)
            }

            let activityIds = activityGroup.activities||[];
            if(activityIds.indexOf(activityId) == -1) activityIds.push(activityId);

            await ActivityGroupModel.setActivitiesToGroupData(groupId, activityIds, ctx.user?.uid);
    
        } catch(e) {
            return ctx.service.utils.resResult(STATUS.INTERNAL_ERR, null, e.stack);
        }
        return ctx.service.utils.resResult(STATUS.SUCCESS)
    }

    /**
     * 将活动组添加入服务器内
     */
    public async saveGroupToServer(groupId: number, serverIds: number[]) {
        const { ctx } = this;
        try {
            await ServerlistModel.pullByGroupId(groupId);
            let servers = await ServerlistModel.findServerByIds(serverIds);
            for(let server of servers) {
                let pushArr: number[] = [], pullArr: number[] = [];
                let activityGroupId = server.activityGroupId||[];
                if(!activityGroupId.includes(groupId)) {
                    pushArr.push(groupId);
                }
                await ServerlistModel.updateActivityGroup(server._id, pushArr, pullArr);
            }
            await ActivityGroupModel.updateServerData(groupId, serverIds, ctx.user?.uid);
        } catch(e) {
            return ctx.service.utils.resResult(STATUS.INTERNAL_ERR, null, e.stack);
        }
        return ctx.service.utils.resResult(STATUS.SUCCESS)
    }

    /**
     * 创建一个新组
     */
    public async createGroup() {
        const { ctx } = this;
        try {
            await ActivityGroupModel.createGroup(ctx.user?.uid);
        } catch(e) {
            return ctx.service.utils.resResult(STATUS.INTERNAL_ERR, null, e.stack);
        }
        return ctx.service.utils.resResult(STATUS.SUCCESS)
    }

    public async deleteGroup(groupId: number) {
        const { ctx } = this;
        try {
            let group = await ActivityGroupModel.findGroupData(groupId);
            if(group) {
                if(group.serverIds.length > 0 || group.activities.length > 0) {
                    return ctx.service.utils.resResult(STATUS.GM_CAN_NOT_DEL_ACT_GROUP);
                }
                await ActivityGroupModel.deleteGroup(groupId);
            }
        } catch(e) {
            return ctx.service.utils.resResult(STATUS.INTERNAL_ERR, null, e.stack);
        }
        return ctx.service.utils.resResult(STATUS.SUCCESS)
    }

    /**
     * 获得活动组类型列表
     */
    public async getActivityGroupTypeList(page: number, pageSize: number, sortField: string, sortOrder: string, groupType: number, groupTypeName: string) {
        const { ctx } = this;
        // console.log('***', page, pageSize, type, serverId, current, activityId)
        const list = await ActivityGroupTypeModel.findByCondition(page, pageSize, sortField, sortOrder, { groupType, groupTypeName });
        const total = await ActivityGroupTypeModel.countByCondition({ groupType, groupTypeName });
        return ctx.service.utils.resResult(STATUS.SUCCESS, {
            list, total
        });
    }
    
    public async updateActivityGroupType(groupType: number|string, groupTypeName: string, activityTypes: number[]) {
        const { ctx } = this;
        let result;
        if(groupType == 'new') {
            result = await ActivityGroupTypeModel.createActivityGroupType(groupTypeName, activityTypes);
        } else if (typeof groupType == 'number') {
            result = await ActivityGroupTypeModel.updateActivityGroupType(groupType, groupTypeName, activityTypes);
        }
        if(!result) return ctx.service.utils.resResult(STATUS.GM_ACTIVITY_GROUP_TYPE_NOT_FOUND);
        return ctx.service.utils.resResult(STATUS.SUCCESS);
    }
    
    public async deleteActivityGroupType(groupType: number) {
        const { ctx } = this;
        await ActivityGroupTypeModel.deleteActivityGroupType(groupType);
        return ctx.service.utils.resResult(STATUS.SUCCESS);
    }
    
    public async saveGroupTypeToActivityGroup(groupId: number, groupType: number) {
        const { ctx } = this;
        let groupTypeObj = await ActivityGroupTypeModel.findByGroupType(groupType);
        if(!groupTypeObj) return ctx.service.utils.resResult(STATUS.GM_ACTIVITY_GROUP_TYPE_NOT_FOUND);
        await ActivityGroupModel.updateGroup(groupId, { type: groupType }, ctx.user?.uid);
        return ctx.service.utils.resResult(STATUS.SUCCESS);
    }

    public async getGroupDataById(groupId: number) {
        const { ctx } = this;
        let activityGroup = await ActivityGroupModel.findGroupData(groupId);
        if(!activityGroup) return ctx.service.utils.resResult(STATUS.GM_ACTIVITY_GROUP_NOT_FOUND);
        let { type, activities: activityIds = [] } = activityGroup;
        let activities = await ActivityModel.findActivityByIds(activityIds);
        return ctx.service.utils.resResult(STATUS.SUCCESS, {
            data: { groupId, groupType: type, activities }
        });
    }

    public async getActivityTaskPoint(page: number, pageSize: number, sortField: string, sortOrder: string, form: {taskType?: number, taskId?: number, activityId?: number}) {
        const { ctx } = this;
        const list = await ActivityTaskPointModel.findByCondition(page, pageSize, sortField, sortOrder, form);
        const total = await ActivityTaskPointModel.countByCondition(form);
        return ctx.service.utils.resResult(STATUS.SUCCESS, {
            list, total
        });
    }
    
    public async createTaskToActivity(taskType: number, activityId: number) {
        const { ctx } = this;
        let dicTask = gameData.tasks.get(taskType);
        if(!dicTask) return ctx.service.utils.resResult(STATUS.WRONG_PARMS);

        for(let [id, dic] of dicTask) {
            await ActivityTaskPointModel.createDataIfNotExist(taskType, id, activityId, dic['point']||0, ctx.user?.uid);
        }
        return ctx.service.utils.resResult(STATUS.SUCCESS);
    }

    public async updateActivityTaskPoint(taskType: number, taskId: number, activityId: number, point: number) {
        const { ctx } = this;
        let result = await ActivityTaskPointModel.updateData(taskType, taskId, activityId, point, ctx.user?.uid);
        if(!result) return ctx.service.utils.resResult(STATUS.WRONG_PARMS);
        return ctx.service.utils.resResult(STATUS.SUCCESS);
    }

    public async delActivityTaskPoint(taskType: number, taskId: number, activityId: number) {
        const { ctx } = this;

        await ActivityTaskPointModel.deleteData(taskType, taskId, activityId);
        return ctx.service.utils.resResult(STATUS.SUCCESS);
    }
}
