'use strict';

const moment = require('moment')

async function verifyYingshi (ctx) {
   let errMsg = '校验萤石摄像头信息失败'
   const { utils: { verifyYingshiInfo } } = ctx.app.fs
   try {
      const { serialNo } = ctx.request.body;

      await verifyYingshiInfo({ serialNo })

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

async function createYingshi (ctx) {
   let errMsg = '萤石摄像头失败'
   const transaction = await ctx.fs.dc.orm.transaction();
   try {
      const { models } = ctx.fs.dc
      const { userId, token } = ctx.fs.api
      const { utils: { verifyYingshiInfo } } = ctx.app.fs

      const {
         id, name, cloudControl, highDefinition, memoryCard,
         voice, kindId, abilityId, rtmp, serialNo, longitude, latitude,
      } = ctx.request.body;
      let handleCameraId = id
      errMsg = (handleCameraId ? '修改' : '添加') + errMsg

      const beloneSecret = await verifyYingshiInfo({ serialNo })

      let storageData = {
         type: 'yingshi', name, cloudControl, highDefinition, memoryCard,
         voice, longitude, latitude, kindId, rtmp,
         serialNo: String(serialNo).toUpperCase(),
         yingshiSecretId: beloneSecret.id
      }

      if (handleCameraId) {
         await models.Camera.update(storageData, {
            where: {
               id: handleCameraId,
            },
            transaction
         })
      } else {
         storageData.createTime = moment().format()
         storageData.createUserId = userId
         storageData.forbidden = false
         const createRes = await models.Camera.create(storageData, {
            transaction
         })
         handleCameraId = createRes.id
      }

      await models.CameraAbilityBind.destroy({
         where: {
            cameraId: handleCameraId
         },
         transaction
      })
      if (abilityId && handleCameraId) {
         let storageData = abilityId.map(aid => {
            return {
               cameraId: handleCameraId,
               abilityId: aid
            }
         })
         if (storageData.length) {
            await models.CameraAbilityBind.bulkCreate(storageData, {
               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 : errMsg
      }
   }
}

async function getNvrSteam (ctx) {
   let errMsg = '获取 NVR 视频流失败'
   try {
      const { streamId } = ctx.query
      const { utils: { getGbCameraLevel3ByStreamId } } = ctx.app.fs

      const nvrRes = await models.Nvr.findOne({
         where: {
            serialNo: streamId,
         }
      })
      if (!nvrRes) {
         errMsg = '没有找到已配置的 NVR 信息'
         throw errMsg
      }

      const cameraRes = await getGbCameraLevel3ByStreamId({ streamId })

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

async function getNvrSteamById (ctx) {
   try {
      const { models } = ctx.fs.dc
      const { nvrId } = ctx.params
      const { utils: { getGbCameraLevel3ByStreamId } } = ctx.app.fs

      const cameraRes = await getGbCameraLevel3ByStreamId({ streamId, errMsg })
      const nvrRes = await models.Nvr.findOne({
         where: {
            id: nvrId
         }
      })
      ctx.status = 200;
      ctx.body = {
         serialNo: nvrRes.dataValues.serialNo,
         stream: cameraRes
      }
   } catch (error) {
      ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
      ctx.status = 400;
      ctx.body = {}
   }
}

async function createNvrCamera (ctx) {
   let errMsg = ''
   const transaction = await ctx.fs.dc.orm.transaction();
   try {
      const { models } = ctx.fs.dc
      const { userId, token } = ctx.fs.api
      const { utils: { getGbCameraLevel3ByStreamId } } = ctx.app.fs
      const data = ctx.request.body
      const { data: camera, serialNo } = data
      if (!serialNo || !camera) {
         errMsg = '参数错误'
         throw errMsg
      }

      const nvrRes = await models.Nvr.findOne({
         where: {
            serialNo
         }
      })

      if (!nvrRes) {
         errMsg = '尚未添加相应的 NVR 设备'
         throw errMsg
      }
      const addedCameraRes = await models.Camera.findAll({
         where: {
            nvrId: nvrRes.id
         }
      })
      const allCameraRes = await getGbCameraLevel3ByStreamId({ streamId: serialNo })

      let createData = []
      let updateData = []
      for (let c of camera) {
         const corCamera = allCameraRes.find(ac => ac.streamid == c.streamid)
         if (corCamera) {
            const addedData = addedCameraRes.find(ac => ac.serialNo == c.streamid)
            if (addedData) {
               updateData.push({
                  ...addedData.dataValues,
                  serialNo: c.streamid,
                  name: c.name,
                  sip: corCamera.sipip,
                  cloudControl: c.cloudControl
               })
            } else {
               createData.push({
                  type: 'nvr',
                  serialNo: c.streamid,
                  name: c.name,
                  sip: corCamera.sipip,
                  cloudControl: c.cloudControl,
                  createTime: moment().format(),
                  createUserId: userId,
                  forbidden: false,
               })
            }
         } else {
            errMsg = '参数错误'
            throw errMsg
         }
      }
      if (createData.length) {
         await models.Camera.bulkCreate(createData, {
            transaction
         })
      }
      if (updateData.length) {
         for (let u of updateData) {
            await models.Camera.update(u, {
               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: errMsg ? undefined : errMsg
      }
   }
}

async function verifyIpcCamera (ctx) {
   let errMsg = '校验萤石摄像头信息失败'
   try {
      const { utils: { verifyIpcInfo } } = ctx.app.fs
      const { serialNo, } = ctx.request.body;
      await verifyIpcInfo({ serialNo })
      ctx.status = 204;
   } catch (error) {
      ctx.status = 400;
      ctx.body = {
         message: typeof error == 'string' ? error : errMsg
      }
   }
}

async function createIpcCamera (ctx) {
   const transaction = await ctx.fs.dc.orm.transaction();
   let errMsg = ' IPC 网络摄像头失败'
   try {
      const { models } = ctx.fs.dc
      const { userId, token } = ctx.fs.api
      const { utils: { verifyIpcInfo } } = ctx.app.fs

      const {
         id, name, cloudControl, memoryCard,
         voice, longitude, latitude, venderId, rtmp,
         serialNo, kindId, abilityId,
      } = ctx.request.body;
      let handleCameraId = id
      errMsg = (handleCameraId ? '修改' : '添加') + errMsg

      let storageData = {
         type: 'ipc', name, cloudControl, memoryCard,
         voice, longitude, latitude, rtmp, venderId,
         serialNo, kindId,
      }

      const gbCameraRes = await verifyIpcInfo({ serialNo })

      storageData.sip = gbCameraRes.dataValues.sipip

      if (handleCameraId) {
         await models.Camera.update(storageData, {
            where: {
               id: handleCameraId,
            },
            transaction
         })
      } else {
         storageData.createTime = moment().format()
         storageData.createUserId = userId
         storageData.forbidden = false
         const createRes = await models.Camera.create(storageData, {
            transaction
         })
         handleCameraId = createRes.id
      }

      // 保存设备能力
      await models.CameraAbilityBind.destroy({
         where: {
            cameraId: handleCameraId
         },
         transaction
      })
      if (abilityId && handleCameraId) {
         let storageData = abilityId.map(aid => {
            return {
               cameraId: handleCameraId,
               abilityId: aid
            }
         })
         if (storageData.length) {
            await models.CameraAbilityBind.bulkCreate(storageData, {
               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 : errMsg
      }
   }
}

async function verifyCascadeCamera (ctx) {
   let errMsg = '校验级联摄像头信息失败'
   try {
      const { utils: { verifyCascadeInfo } } = ctx.app.fs
      const { sip } = ctx.request.body
      await verifyCascadeInfo({ sip })
      ctx.status = 204;
   } catch (error) {
      ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
      ctx.status = 400;
      ctx.body = {
         message: typeof error == 'string' ? error : errMsg
      }
   }
}

async function createCascadeCamera (ctx) {
   let errMsg = '添加级联摄像头信息失败'
   try {
      const { userId, token } = ctx.fs.api
      const { sip, externalDomain, cascadeType } = ctx.request.body
      const { utils: { getGbCameraLevel3ByStreamId, verifyCascadeInfo } } = ctx.app.fs
      const cameraParentRes = await verifyCascadeInfo({ sip })

      const allCameraRes = await getGbCameraLevel3ByStreamId({ streamId: cameraParentRes.streamid })

      const allCameraIds = allCameraRes.map(c => c.streamid)
      const addedCmeraRes = allCameraIds.length ?
         await models.Camera.findAll({
            where: {
               type: 'cascade',
               serialNo: { $in: allCameraIds }
            }
         }) : []
      let addData = []
      let updateData = []
      for (let { dataValues: c } of allCameraRes) {
         let storageData = {
            externalDomain,
            cascadeType,
            sip: c.sipip,
            name: c.name
         }
         const added = addedCmeraRes.some(ac => ac.streamid == c.streamid)
         if (added) {
            updateData.push({
               ...storageData,
               id: added.id,
            })
         } else {
            addData.push({
               ...storageData,
               serialNo: c.streamid,
               createTime: moment().format(),
               createUserId: userId,
               forbidden: false
            })
         }
      }
      ctx.status = 204;
   } catch (error) {
      ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
      ctx.status = 400;
      ctx.body = {
         message: typeof error == 'string' ? error : errMsg
      }
   }
}

module.exports = {
   verifyYingshi,
   createYingshi,
   getNvrSteam,
   getNvrSteamById,
   createNvrCamera,
   verifyIpcCamera,
   createIpcCamera,
   verifyCascadeCamera,
   createCascadeCamera,
};