'use strict';
const moment = require('moment')

async function edit (ctx) {
   const transaction = await ctx.fs.dc.orm.transaction();
   try {
      const sequelize = ctx.fs.dc.orm;
      const { models } = ctx.fs.dc;
      const { userId } = ctx.fs.api
      const data = ctx.request.body
      const timeNow = moment()
      const { mirrorId, tree = [], filterGroup = [] } = data
      let mirrorId_ = mirrorId

      if (mirrorId_) {
         let upData = {
            template: data.template,
            updateTime: timeNow.format(),
            title: data.title,
            showHeader: Boolean(data.showHeader),
         }
         if (data.publish) {
            upData.publish = true
            upData.publishTime = timeNow.format()
         }
         await models.Mirror.update(upData, {
            where: {
               id: mirrorId_
            },
            transaction
         })

         // 除 Mirror 外的信息全删除并重建
         await models.MirrorCamera.destroy({
            where: {
               mirrorId: mirrorId_
            },
            transaction
         })
         await sequelize.query('DELETE FROM mirror_filter WHERE group_id IN (SELECT id FROM mirror_filter_group WHERE mirror_id=?)', {
            replacements: [mirrorId_],
            transaction
         })
         await models.MirrorFilterGroup.destroy({
            where: {
               mirrorId: mirrorId_
            },
            transaction
         })
         await models.MirrorTree.destroy({
            where: {
               mirrorId: mirrorId_
            },
            transaction
         })
      } else {
         // 创建 镜像信息
         let createData = {
            template: data.template,
            createUser: userId,
            createTime: timeNow.format(),
            title: data.title,
            showHeader: Boolean(data.showHeader),
            publish: false,
            mid: timeNow.format(`ssmmHHDDMMYYYY`)
         }
         if (data.publish) {
            createData.publish = true
            createData.publishTime = timeNow.format()
         }
         const mirrorCreateRes = await models.Mirror.create(createData, {
            transaction
         })
         mirrorId_ = mirrorCreateRes.id
      }

      let cameraStorage = {}
      const dealTree = async (child, lastNodeStorageId, level) => {
         // 递归 tree 获得扁平信息
         let curLevel = level
         for (let c of child) {
            if (c.cameraId) {
               // 摄像头节点为末端节点
               // 不创建节点
               if (cameraStorage[c.cameraId]) {
                  cameraStorage[c.cameraId].treeIds.push(lastNodeStorageId)
               } else {
                  cameraStorage[c.cameraId] = {
                     treeIds: [lastNodeStorageId],
                     filterIds: []
                  }
               }
            } else {
               const treeStorageRes = await models.MirrorTree.create({
                  name: c.label,
                  level: curLevel,
                  dependence: lastNodeStorageId,
                  mirrorId: mirrorId_
               }, {
                  transaction
               })

               if (c.children) {
                  await dealTree(c.children, treeStorageRes.id, curLevel + 1)
               }
            }
         }
      }
      await dealTree(tree, null, 1)

      for (let g of filterGroup) {
         // 遍历创建筛选分组
         const filterGroupStorageRes = await models.MirrorFilterGroup.create({
            name: g.name,
            forbidden: g.forbidden,
            mirrorId: mirrorId_
         }, {
            transaction
         })
         if (g.filters) {
            for (let f of g.filters) {
               // 遍历创建筛选项
               const filterStorageRes = await models.MirrorFilter.create({
                  name: f.name,
                  groupId: filterGroupStorageRes.id
               }, {
                  transaction
               })
               for (let cid of f.cameraIds) {
                  if (cameraStorage[cid]) {
                     cameraStorage[cid].filterIds.push(filterStorageRes.id)
                  }
               }
            }
         }
      }

      let bulkCreateCameraD = []
      for (let cid in cameraStorage) {
         bulkCreateCameraD.push({
            cameraId: cid,
            ...cameraStorage[cid],
            mirrorId: mirrorId_
         })
      }
      if (bulkCreateCameraD.length) {
         await models.MirrorCamera.bulkCreate(bulkCreateCameraD, {
            transaction
         })
      }

      await transaction.commit();
      ctx.status = 204;
   } catch (error) {
      await transaction.rollback();
      ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
      ctx.status = 400;
      ctx.body = {
         message: typeof error == 'string' ? error : undefined
      }
   }
}

async function list (ctx) {
   try {
      const { models } = ctx.fs.dc;
      const { userId, token } = ctx.fs.api

      const mirrorRes = await models.Mirror.findAll({
         attributes: {
            exclude: ['showHeader']
         },
         where: {},
         order: [['id', 'DESC']]
      })
      let createUserIds = new Set()

      for (let c of mirrorRes) {
         createUserIds.add(c.dataValues.createUser)
      }

      // 查对应创建者信息
      const corUsers = await ctx.app.fs.authRequest.get(`user/${[...createUserIds].join(',') || -1}/message`, { query: { token } })
      for (let { dataValues: mirror } of mirrorRes) {
         const corUser = corUsers.find(u => u.id == mirror.createUser)
         mirror.createUser = corUser ? corUser.username : ''
      }

      ctx.status = 200;
      ctx.body = mirrorRes
   } catch (error) {
      ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
      ctx.status = 400;
      ctx.body = {
         message: typeof error == 'string' ? error : undefined
      }
   }
}

async function get (ctx) {
   try {
      // 下次这样的关关联联要用数据库关联 !!!
      // 不然逻辑好绕啊
      const { models } = ctx.fs.dc;
      const { userId } = ctx.fs.api
      const { mid } = ctx.params
      // 查当前镜像的全部信息
      const mirrorRes = await models.Mirror.findOne({
         attributes: {
            exclude: ['createUser']
         },
         order: [['id', 'ASC']],
         where: {
            mid: mid
         },
         include: [{
            model: models.MirrorTree,
            required: false
         }, {
            model: models.MirrorFilterGroup,
            attributes: {
               exclude: ['mirrorId']
            },
            required: false,
            include: [{
               model: models.MirrorFilter,
               attributes: {
                  exclude: ['groupId']
               },
               required: false
            }]
         }, {
            model: models.MirrorCamera,
            required: false,
            include: {
               model: models.Camera,
               attributes: {
                  exclude: ['rtmp', 'venderId', 'createTime', 'recycleTime', 'delete', 'createUserId', 'nvrId', 'kindId', 'yingshiSecretId', 'gbId']
               },
               include: [{
                  model: models.SecretYingshi,
                  attributes: ['token']
               }, {
                  model: models.GbCamera,
                  attributes: ['id', 'online', 'playUrl',],
                  required: false
               }, {
                  model: models.CameraRemark,
                  attributes: ['remark'],
                  order: [
                     ['id', 'DESC']
                  ],
               }]
            }
         }]
      })

      let returnData
      if (mirrorRes) {
         const { mirrorCameras, mirrorFilterGroups, mirrorTrees } = mirrorRes.dataValues
         returnData = {
            ...mirrorRes.dataValues,
            tree: [],
            filterGroup: []
         }

         // 反向构建出树节点
         const buildTree = (treeNodes = [], lastLevelKey = '') => {
            const nextKeyPre = lastLevelKey ? lastLevelKey + '-' : lastLevelKey
            treeNodes.forEach((tn, index) => {
               const curKey = nextKeyPre + index
               let child = JSON.parse(JSON.stringify(mirrorTrees.filter(mt => mt.dependence == tn.id)))
               let cameras = mirrorCameras.filter(mc => mc.treeIds.includes(tn.id))
               if (cameras.length) {
                  // 有摄像头 向下再创建一级节点
                  tn.children = cameras.map((c, cIndex) => {
                     return {
                        label: c.dataValues.camera.name,
                        key: curKey + '-' + cIndex,
                        cameraId: c.dataValues.cameraId,
                        camera: c.dataValues.camera
                     }
                  })
               } else {
                  tn.children = child
                  buildTree(child, curKey)
               }
               tn.label = tn.name
               tn.key = curKey

               delete tn.name
               delete tn.level
               delete tn.dependence
               delete tn.mirrorId
            })
         }
         let tree = JSON.parse(JSON.stringify(mirrorTrees.filter(t => t.level == 1)))
         buildTree(tree)
         returnData.tree = tree

         // 构建筛选分组及筛选项
         for (let { dataValues: g } of mirrorFilterGroups) {
            for (let { dataValues: f } of g.mirrorFilters) {
               f.cameraIds = (mirrorCameras.filter(mc => mc.filterIds.includes(f.id)) || []).map(mc => mc.cameraId)
            }
            g.filters = g.mirrorFilters
            delete g.mirrorFilters
         }
         returnData.filterGroup = mirrorFilterGroups

         delete returnData.mirrorCameras
         delete returnData.mirrorFilterGroups
         delete returnData.mirrorTrees
      } else {
         throw '没有查询到对应的镜像服务'
      }

      ctx.status = 200;
      ctx.body = returnData
   } catch (error) {
      ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
      ctx.status = 400;
      ctx.body = {
         message: typeof error == 'string' ? error : undefined
      }
   }
}

async function del (ctx) {
   const transaction = await ctx.fs.dc.orm.transaction();
   try {
      const { models } = ctx.fs.dc;
      const { userId } = ctx.fs.api
      const { mirrorId } = ctx.params

      if (!mirrorId) throw '镜像服务删除失败';

      const sequelize = ctx.fs.dc.orm;
      // 除 Mirror 外的信息全删除并重建
      await models.MirrorCamera.destroy({
         where: {
            mirrorId: mirrorId
         },
         transaction
      })
      await sequelize.query('DELETE FROM mirror_filter WHERE group_id IN (SELECT id FROM mirror_filter_group WHERE mirror_id=?)', {
         replacements: [mirrorId],
         transaction
      })
      await models.MirrorFilterGroup.destroy({
         where: {
            mirrorId: mirrorId
         },
         transaction
      })
      await models.MirrorTree.destroy({
         where: {
            mirrorId: mirrorId
         },
         transaction
      })
      await models.Mirror.destroy({
         where: {
            id: mirrorId
         },
         transaction
      })

      await transaction.commit();
      ctx.status = 204;
   } catch (error) {
      await transaction.rollback();
      ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
      ctx.status = 400;
      ctx.body = {
         message: typeof error == 'string' ? error : undefined
      }
   }
}

async function publish (ctx) {
   try {
      const { models } = ctx.fs.dc;
      const { userId } = ctx.fs.api
      const { mirrorId } = ctx.params

      if (!mirrorId) throw '发布镜像服务失败';

      await models.Mirror.update({
         publish: true,
         publishTime: moment().format()
      }, {
         where: {
            id: mirrorId
         }
      })

      ctx.status = 204;
   } catch (error) {
      ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
      ctx.status = 400;
      ctx.body = {
         message: typeof error == 'string' ? error : undefined
      }
   }
}

async function copy (ctx) {
   const transaction = await ctx.fs.dc.orm.transaction();
   try {
      const { models } = ctx.fs.dc;
      const { userId } = ctx.fs.api
      const { mirrorId } = ctx.params
      const timeNow = moment()
      // 查当前镜像的全部信息
      const mirrorRes = await models.Mirror.findOne({
         attributes: {
            exclude: ['createUser']
         },
         order: [['id', 'ASC']],
         where: {
            id: mirrorId
         },
         include: [{
            model: models.MirrorTree,
            required: false
         }, {
            model: models.MirrorFilterGroup,
            required: false,
            include: [{
               model: models.MirrorFilter,
               required: false
            }]
         }, {
            model: models.MirrorCamera,
            required: false,
         }]
      })

      if (mirrorRes) {
         const { mirrorCameras, mirrorFilterGroups, mirrorTrees } = mirrorRes.dataValues

         const newMirrorRes = await models.Mirror.create({
            template: mirrorRes.template,
            createUser: userId,
            createTime: timeNow.format(),
            title: mirrorRes.title + '-副本',
            showHeader: mirrorRes.showHeader,
            publish: mirrorRes.publish,
            mid: timeNow.format(`ssmmHHDDMMYYYY`)
         }, {
            transaction
         })

         const newMirrorId = newMirrorRes.id
         let cameraStorage = {}

         // 重新存一遍树节点
         const storageTree = async (node, lastNodeStorageId) => {
            for (let n of node) {
               // 创建新节点
               const newTreeNodeStorageRes = await models.MirrorTree.create({
                  name: n.name,
                  level: n.level,
                  dependence: lastNodeStorageId,
                  mirrorId: newMirrorId
               }, {
                  transaction
               })
               // 筛选老节点所下辖的摄像头
               let corCamera = mirrorCameras.filter((mc) => mc.treeIds.includes(n.id))
               for (let c of corCamera) {
                  // 为摄像头存新的节点id
                  if (cameraStorage[c.cameraId]) {
                     cameraStorage[c.cameraId].treeIds.push(newTreeNodeStorageRes.id)
                  } else {
                     cameraStorage[c.cameraId] = {
                        treeIds: [newTreeNodeStorageRes.id],
                        filterIds: []
                     }
                  }
               }
               const nextNode = mirrorTrees.filter(mt => mt.dependence == n.id)
               if (nextNode.length) {
                  await storageTree(nextNode)
               }
            }
         }
         let treeLevelOne = mirrorTrees.filter(mt => mt.level == 1)
         await storageTree(treeLevelOne, null)

         // 重新存一遍筛选分组、筛选项
         for (let { dataValues: g } of mirrorFilterGroups) {
            const newGroupStorageRes = await models.MirrorFilterGroup.create({
               name: g.name,
               forbidden: g.forbidden,
               mirrorId: newMirrorId
            }, {
               transaction
            })
            for (let { dataValues: f } of g.mirrorFilters) {
               const newFilterStorageRes = await models.MirrorFilter.create({
                  name: f.name,
                  groupId: newGroupStorageRes.id
               }, {
                  transaction
               })
               let corCamera = mirrorCameras.filter((mc) => mc.filterIds.includes(f.id))
               for (let c of corCamera) {
                  // 为摄像头存新的节点id
                  if (cameraStorage[c.cameraId]) {
                     cameraStorage[c.cameraId].filterIds.push(newFilterStorageRes.id)
                  }
               }
            }
         }
         let bulkCreateCameraD = []
         for (let cid in cameraStorage) {
            bulkCreateCameraD.push({
               cameraId: cid,
               ...cameraStorage[cid],
               mirrorId: newMirrorId
            })
         }
         if (bulkCreateCameraD.length) {
            await models.MirrorCamera.bulkCreate(bulkCreateCameraD, {
               transaction
            })
         }
      }

      await transaction.commit();
      ctx.status = 204;
   } catch (error) {
      await transaction.rollback();
      ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
      ctx.status = 400;
      ctx.body = {
         message: typeof error == 'string' ? error : undefined
      }
   }
}

module.exports = {
   edit,
   list,
   get,
   del,
   publish,
   copy,
};