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

async function edit (ctx, next) {
   let errMsg = '添加 NVR 设备失败'
   const transaction = await ctx.fs.dc.orm.transaction();
   try {
      const { utils: { getGbCameraLevel3ByStreamId } } = ctx.app.fs
      const { models } = ctx.fs.dc;
      const { userId } = ctx.fs.api
      const data = ctx.request.body;
      const { serialNo } = data

      const nvrGbRes = await models.GbCamera.findOne({
         where: {
            streamid: serialNo,
            level: 0,
            // ipctype: 'nvr'
         }
      })

      if (!nvrGbRes) {
         errMsg = '没有找到已接入的 NVR 服务信息'
         throw errMsg
      }

      const channelRes = await getGbCameraLevel3ByStreamId({ streamId: serialNo, errMsg })

      // 或取其他服务信息
      const nvrData = {
         channelCount: channelRes.length,
         port: 8080,
         sip: nvrGbRes.sipip,
      }

      if (data.id) {
         // 修改
         const storageData = Object.assign({}, data, nvrData)
         await models.Nvr.update(storageData, {
            where: {
               id: data.id
            },
            transaction
         })
      } else {
         // 添加
         const storageData = Object.assign({}, data, nvrData, {
            createTime: moment().format(),
            createUserId: userId,
            delete: false,
         })
         await models.Nvr.create(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: errMsg
      }
   }
}

async function verify (ctx, next) {
   let errMsg = '校验 NVR 设备信息失败'
   try {
      const { models } = ctx.fs.dc;
      const { userId } = ctx.fs.api
      const data = ctx.request.body;
      const { serialNo } = data

      const nvrGbRes = await models.GbCamera.findOne({
         where: {
            streamid: serialNo,
            level: 0,
            // ipctype: 'nvr'
         }
      })

      if (!nvrGbRes) {
         errMsg = '没有找到已接入的 NVR 服务信息'
         throw errMsg
      }

      ctx.status = 204;
   } catch (error) {
      ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
      ctx.status = 400;
      ctx.body = {
         resaon: errMsg
      }
   }
}

async function get (ctx) {
   try {
      const models = ctx.fs.dc.models;
      const { userId, token } = ctx.fs.api
      const { limit, page, orderBy, orderDirection, keyword, venderId, state } = ctx.query
      let findOption = {
         attributes: { exclude: ['delete'] },
         where: {
            createUserId: userId,
            delete: false,
         },
         order: [
            [orderBy || 'id', orderDirection || 'DESC']
         ],
         include: [],
         distinct: true
      }
      let gbNvrOption = {
         model: models.GbCamera,
         as: 'gbNvr',
         // attributes: ['id', 'address', 'name', 'online'],
         required: false
      }

      if (limit) {
         findOption.limit = limit
      }
      if (page && limit) {
         findOption.offset = page * limit
      }
      if (keyword) {
         findOption.where.name = { $like: `%${keyword}%` }
      }
      if (venderId) {
         findOption.where.venderId = venderId
      }
      if (state) {
         const onLineMap = {
            ON: ['ON', 'ONLINE'],
            OFF: ['OFF'],
            // UNKONW: [],
            DISABLED: []
         }

         let unknowState = []
         for (let k in onLineMap) {
            unknowState = unknowState.concat(onLineMap[k])
         }

         gbNvrOption.where = {
            online: state == 'UNKONW' ?
               { $notIn: unknowState }
               : { $in: onLineMap[state] }
         }
         gbNvrOption.required = true
      }

      findOption.include.push(gbNvrOption)

      const nvrRes = await models.Nvr.findAndCountAll(findOption)

      const nvrIds = nvrRes.rows.map(r => r.id)
      const cameraRes = await models.Camera.findAll({
         where: {
            nvrId: { $in: nvrIds }
         }
      })
      let createUserIds = new Set()
      let cameraIds = []
      for (let c of cameraRes) {
         cameraIds.push(c.id)
         createUserIds.add(c.createUserId)
      }

      // 查在安心云绑定的数据
      const axbindCameraRes = cameraIds.length ?
         await ctx.app.fs.axyRequest.get('vcmp/camera/project', { query: { token, cameraId: cameraIds.join(',') } })
         : []

      // 查用户信息
      const createUserRes = await ctx.app.fs.authRequest.get(`user/${[...createUserIds].join(',') || -1}/message`, { query: { token } })

      for (let { dataValues: n } of nvrRes.rows) {
         const corCameras = cameraRes.filter(c => c.nvrId == n.id)
         const corBind = axbindCameraRes.filter(b => corCameras.some(c => c.id == b.cameraId))
         const corCreateUser = createUserRes.find(u => u.id == n.createUserId)

         n.createUser = {
            name: corCreateUser ? corCreateUser.username : ''
         }
         if (corBind.length) {
            n.station = []
            for (let c of corBind) {
               n.station = n.station.concat(c.stations)
            }
         } else {
            n.station = []
         }
      }

      ctx.status = 200;
      ctx.body = {
         total: nvrRes.count,
         data: nvrRes.rows
      }
   } catch (error) {
      ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
      ctx.status = 400;
      ctx.body = {}
   }
}

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

      await models.Nvr.destroy({
         where: {
            id: nvrId
         },
         transaction
      })

      const cameraRes = await models.Camera.findAll({
         where: {
            nvrId
         }
      })

      const cameraIds = cameraRes.map(c => c.id)

      await models.Camera.destroy({
         where: {
            nvrId,
         }
      })
      if (cameraIds.length) {
         await ctx.app.fs.axyRequest.delete('vcmp/camera/project', { query: { token, cameraId: cameraIds.join(',') } })
      }

      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 = {}
   }
}

async function detail (ctx) {
   let errMsg = '获取 NVR 详情失败'
   try {
      const models = ctx.fs.dc.models;
      const { userId, token } = ctx.fs.api
      const { nvrId } = ctx.params

      const nvrRes = await models.Nvr.findOne({
         attributes: { exclude: ['delete'] },
         where: {
            id: nvrId
         },
         include: [{
            model: models.Vender
         }, {
            model: models.GbCamera,
            as: 'gbNvr',
            // attributes: ['id', 'address', 'name', 'online', 'registerTime', 'updateTime'],
            required: false
         }]
      })

      if (!nvrRes) {
         throw errMsg
      }

      // 查询对应的后端服务相关信息

      const cameraRes = await models.Camera.findAll({
         attributes: ['id', 'name', 'channelName', 'serialNo', 'rtmp'],
         where: {
            nvrId
         }
      })
      let cameras = []
      let cameraIds = []
      for (let c of cameraRes) {
         cameraIds.push(c.id)
         cameras.push(c.dataValues)
      }

      const cameraProject = await ctx.app.fs.axyRequest.get('vcmp/camera/project', { query: { token, cameraId: cameraIds.join(',') } })
      const bindStations = []
      for (let c of cameraProject) {
         for (let s of c.stations) {
            bindStations.push(s)
         }
      }

      const corUser = await ctx.app.fs.authRequest.get(`user/${nvrRes.createUserId || -1}/message`, { query: { token } })
      // const serverDRes = (await ctx.app.fs.videoServerRequest.post(`gb28181/api/plugins`) || '')
      const serverDRes = (await ctx.app.fs.videoServerRequest.post(`gateway/plugins`) || '')
      const serverDArr = JSON.parse(serverDRes.replace(/'/g, '"')) || []
      const serverDConfig = serverDArr.find(s => s.Name == 'GB28181')
      let serveD = {}
      if (serverDConfig) {
         const { Config } = serverDConfig
         let ConfigArr = Config.split('\n')
         for (let c of ConfigArr) {
            let config = c.split(' = ')
            if (config.length == 2) {
               serveD[config[0].trim()] = config[1].trim().replace(/\"/g, '')
            }
         }
      }
      let nvrDetail = {
         ...nvrRes.dataValues,
         station: bindStations,
         camera: cameras,
         createUser: {
            namePresent: corUser.length ? corUser[0].namePresent : ''
         },
         accessWay: 'GB/T28181',
         accessInfo: serveD
      }

      ctx.status = 200;
      ctx.body = nvrDetail
   } catch (error) {
      ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
      ctx.status = 400;
      ctx.body = { message: errMsg }
   }
}

async function nvrExport (ctx) {
   try {
      const { models } = ctx.fs.dc
      const { userId, token } = ctx.fs.api
      const { utils: { simpleExcelDown } } = ctx.app.fs

      const header = [{
         title: "设备名称",
         key: "name",
      }, {
         title: "SIP地址",
         key: "sip",
      }, {
         title: "设备厂家",
         key: "vender",
      }, {
         title: "添加账号",
         key: "createUser",
      }, {
         title: "通道数",
         key: "channelCount",
      }, {
         title: "端口",
         key: "port",
      }, {
         title: "设备状态",
         key: "state",
      }, {
         title: "创建时间",
         key: "createTime",
      }, {
         title: "项目名称",
         key: "projectName",
      }, {
         title: "pcode",
         key: "pcode",
      }, {
         title: "结构物",
         key: "structure",
      },];

      const nvrRes = await models.Nvr.findAll({
         where: {
            createUserId: userId,
         },
         include: [{
            model: models.Vender
         }]
      })
      const nvrIds = nvrRes.map(r => r.id)
      const cameraRes = await models.Camera.findAll({
         where: {
            nvrId: { $in: nvrIds }
         }
      })
      let createUserIds = new Set()
      let cameraIds = []
      for (let c of cameraRes) {
         cameraIds.push(c.id)
         createUserIds.add(c.createUserId)
      }

      // 查在安心云绑定的数据
      const axbindCameraRes =
         cameraIds.length ?
            await ctx.app.fs.axyRequest.get('vcmp/camera/project', { query: { token, cameraId: cameraIds.join(',') } })
            : []

      // 查用户信息
      const createUserRes = await ctx.app.fs.authRequest.get(`user/${[...createUserIds].join(',') || -1}/message`, { query: { token } })

      let exportData = []
      for (let { dataValues: n } of nvrRes) {
         const corCameras = cameraRes.filter(c => c.nvrId == n.id)
         const corBind = axbindCameraRes.filter(b => corCameras.some(c => c.id == b.cameraId))
         const corCreateUser = createUserRes.find(u => u.id == n.createUserId)

         n.createUser = {
            name: corCreateUser ? corCreateUser.username : ''
         }

         n.vender = n.vender ? n.vender.name : ''
         n.createTime = moment(n.createTime).format('YYYY-MM-DD HH:mm:ss')

         let projectName = new Set(),
            pcode = new Set(),
            structure = new Set();
         if (corBind.length) {
            for (let c of corBind) {
               for (let station of c.stations) {
                  structure.add(station.structure.name)
                  for (let project of station.structure.projects) {
                     projectName.add(project.name)
                     pcode.add(project.url)
                  }
               }
            }
         }
         n.projectName = [...projectName].join('\r\n')
         n.pcode = [...pcode].join('\r\n')
         n.structure = [...structure].join('\r\n')

         exportData.push(n)
      }

      const fileName = `NVR信息列表_${userId}_${moment().format('YYYYMMDDHHmmss')}` + '.csv'
      const filePath = await simpleExcelDown({ data: exportData, header, fileName: fileName })
      const fileData = fs.readFileSync(filePath);
      ctx.status = 200;
      ctx.set('Content-Type', 'application/x-xls');
      ctx.set('Content-disposition', 'attachment; filename=' + encodeURI(fileName));
      ctx.body = fileData;
   } catch (error) {
      ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
      ctx.status = 400;
      ctx.body = {}
   }
}

module.exports = {
   edit,
   verify,
   get,
   del,
   detail,
   nvrExport,
};