'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,
         channelNo,
      } = ctx.request.body;
      let handleCameraId = id
      errMsg = (handleCameraId ? '修改' : '添加') + errMsg

      const beloneSecret = await verifyYingshiInfo({ serialNo })
      const corGbYingshiRes = await models.GbCamera.findOne({
         where: {
            streamid: String(serialNo).toUpperCase(),
            ipctype: 'yingshi'
         }
      })
      let storageData = {
         type: 'yingshi', name, cloudControl, highDefinition, memoryCard,
         voice, longitude, latitude, kindId, rtmp,
         serialNo: String(serialNo).toUpperCase(),
         yingshiSecretId: beloneSecret.id,
         gbId: corGbYingshiRes ? corGbYingshiRes.id : null,
         channelNo,
      }

      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 { models } = ctx.fs.dc
      const { streamId } = ctx.query
      const { utils: { getGbCameraLevel3ByStreamId, getPlayUrl } } = ctx.app.fs

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

      const addedRes = await models.Camera.findAll({
         attributes: ['id', 'name', 'serialNo', 'cloudControl'],
         where: {
            nvrId: nvrRes.id
         },
         include: [{
            model: models.CameraRemark,
            attributes: ['remark'],
            order: [
               ['id', 'DESC']
            ],
         }],
      })

      const cameraRes = await getGbCameraLevel3ByStreamId({ streamId })

      for (let c of cameraRes) {
         let preAdd = addedRes.find(ad => ad.dataValues.serialNo == c.streamid)
         if (preAdd) {
            c.dataValues.camera = preAdd.dataValues
         } else {
            c.dataValues.camera = null
         }
         c.dataValues.playUrl = await getPlayUrl({ topSerialNo: streamId, serialNo: c.dataValues.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,
                  topSerialNo: serialNo,
                  name: c.name,
                  sip: corCamera.sipip,
                  cloudControl: c.cloudControl,
                  gbId: corCamera.id,
               })
            } else {
               createData.push({
                  type: 'nvr',
                  serialNo: c.streamid,
                  topSerialNo: serialNo,
                  name: c.name,
                  sip: corCamera.sipip,
                  cloudControl: c.cloudControl,
                  nvrId: nvrRes.id,
                  createTime: moment().format(),
                  createUserId: userId,
                  forbidden: false,
                  gbId: corCamera.id,
               })
            }
         } 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, {
               where: {
                  id: u.id
               },
               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.sipip
      storageData.gbId = gbCameraRes.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 getCascadeSipList (ctx) {
   try {
      const { models } = ctx.fs.dc

      const sipListRes = await models.GbCamera.findAll({
         attributes: ['id', 'streamid', 'sipip'],
         where: {
            level: 0,
            ipctype: '级联',
            // sipip: { $ne: null }
         }
      })
      ctx.status = 200;
      ctx.body = sipListRes
   } catch (error) {
      ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
      ctx.status = 400;
      ctx.body = {}
   }
}

async function verifyCascadeCamera (ctx) {
   let errMsg = '校验级联摄像头信息失败'
   try {
      const { utils: { verifyCascadeInfo } } = ctx.app.fs
      const { streamId } = ctx.request.body
      await verifyCascadeInfo({ streamId })
      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 getCascadeSteam (ctx) {
   let errMsg = '获取级联摄像头视频流失败'
   try {
      const { models } = ctx.fs.dc
      const { streamId } = ctx.query
      const { utils: { getGbCameraLevel3ByStreamId, getPlayUrl } } = ctx.app.fs

      const cascadeRes = await models.GbCamera.findOne({
         where: {
            streamid: streamId
         }
      })
      if (!cascadeRes) {
         errMsg = '没有找到已记录的级联摄像头信息'
         throw errMsg
      }

      const cameraRes = await getGbCameraLevel3ByStreamId({ streamId: cascadeRes.streamid })
      const allStreamid = cameraRes.map(c => c.streamid)
      const addedRes = await models.Camera.findAll({
         attributes: ['id', 'name', 'serialNo'],
         where: {
            serialNo: { $in: allStreamid }
         },
         include: [{
            model: models.CameraRemark,
            attributes: ['remark'],
            order: [
               ['id', 'DESC']
            ],
         }],
      })

      for (let c of cameraRes) {
         let preAdd = addedRes.find(ad => ad.dataValues.serialNo == c.streamid)
         if (preAdd) {
            c.dataValues.camera = preAdd.dataValues
         } else {
            c.dataValues.camera = null
         }
         c.dataValues.playUrl = await getPlayUrl({ topSerialNo: cascadeRes.streamid, serialNo: c.dataValues.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 getCascadeCameraGrandParentSip (ctx) {
   let errMsg = '查询级联设备失败'
   try {
      const { models } = ctx.fs.dc
      const { cameraSerialNo } = ctx.query
      const { utils: { getGbCameraLevel1ByStreamId } } = ctx.app.fs

      const parent = await getGbCameraLevel1ByStreamId({
         streamId: cameraSerialNo,
         where: { ipctype: '级联' }
      })
      if (!parent) {
         errMsg = `没有找到相应级联设备`
         throw errMsg
      }
      ctx.status = 200;
      ctx.body = parent
   } 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 = '添加级联摄像头信息失败'
   const transaction = await ctx.fs.dc.orm.transaction();
   try {
      const { models } = ctx.fs.dc
      const { userId, token } = ctx.fs.api
      const { streamId, camera = [], externalDomain, cascadeType } = ctx.request.body
      const { utils: { getGbCameraLevel3ByStreamId, verifyCascadeInfo } } = ctx.app.fs
      const cameraParentRes = await verifyCascadeInfo({ streamId })

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

      const allCameraIds = allCameraRes.map(c => c.id)
      const addedCmeraRes = allCameraIds.length ?
         await models.Camera.findAll({
            where: {
               type: 'cascade',
               gbId: { $in: allCameraIds },
               delete: false
            }
         }) : []
      let addData = []
      let updateData = []
      for (let c of camera) {
         const corGbCamera = allCameraRes.find(ac => ac.id == c.id)
         if (!corGbCamera) {
            errMsg = '数据信息错误'
            throw errMsg
         }
         let storageData = {
            externalDomain,
            cascadeType,
            serialNo: corGbCamera.streamid,
            topSerialNo: cameraParentRes.streamid,
            sip: corGbCamera.sipip,
            name: c.name,
            gbId: corGbCamera.id,
         }
         const added = addedCmeraRes.find(ac => ac.gbId == corGbCamera.id)
         if (added) {
            let data = {
               ...storageData,
               id: added.id,
            }
            updateData.push(data)
            await models.Camera.update(data, {
               where: { id: added.id },
               transaction
            })
         } else {
            addData.push({
               ...storageData,
               type: 'cascade',
               createTime: moment().format(),
               createUserId: userId,
               forbidden: false
            })
         }
      }
      await models.Camera.bulkCreate(addData, {
         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
      }
   }
}

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