/* eslint-disable no-inner-declarations */
process.on('message', async (message, setHandle) => {
  try {
    const [dllPath, port] = require('path').join(message).split('|')
    process.send({ rescode: 0, msg: [dllPath, port] })
    const ffi = require('ffi')
    const ref = require('ref')
    const Struct = require('ref-struct')
    const RefArray = require('ref-array')
    const bufferTrim = require('buffertrim')

    const rescode = {
      65536: 'success',
      65537: 'fail',
      66306: 'timeout',
      66305: 'cancel'
    }

    const Sodo_RequestCardAndQrcode = Struct({
      transType: 'char',
      transDate: RefArray(ref.types.char, 3),
      transTime: RefArray(ref.types.char, 3),
      transAmt: 'int',
      transNo: RefArray(ref.types.char, 4),
      transOutBuf: RefArray(ref.types.char, 4096),
      lenTransOutbuf: 'int'
    })

    const CardInfo = Struct({
      recvBuf: RefArray(ref.types.char, 4096),
      lenRecv: 'int'
    })

    const SfzInfo = Struct({
      cmdOp1: ref.types.byte,
      cmdOp2: ref.types.byte,
      dataSend: RefArray(ref.types.char, 1024),
      lendataSend: 'int',
      recvBuf: RefArray(ref.types.byte, 4096),
      lenRecv: 'int'
    })

    let program = ffi.Library(dllPath, {
      Sodo_InitSerialPort: ['void', ['int', 'int']],
      // Sodo_InitHttps: ["void", ["int"]],
      Sodo_Start: ['int', []],
      Sodo_Stop: ['int', []],
      // Sodo_Stop: ["int", []],
      Sodo_SB_Process: ['int', [ref.refType(CardInfo)]],
      Sodo_SB_Psam_Process_GetAllInfo: ['int', ['int*', 'int*', 'int']],
      '_Sodo_Sfz_Process@4': ['int', [ref.refType(SfzInfo)]],
      '_Sodo_RequestCardAndQrcode@4': [
        'int',
        [ref.refType(Sodo_RequestCardAndQrcode)]
      ]
    })

    function search () {
      try {
        const cardAndQrcode = new Sodo_RequestCardAndQrcode()

        cardAndQrcode.transType = 0x60
        cardAndQrcode.transDate = [0x20, 0x12, 0x12]
        cardAndQrcode.transNo = [0x11, 0x22, 0x33, 0x44]
        cardAndQrcode.transAmt = 1

        const ret = program['_Sodo_RequestCardAndQrcode@4'](cardAndQrcode.ref())

        if (rescode[ret] === 'timeout' || rescode[ret] === 'cancel') {
          process.send({ rescode: 0, msg: '连接超时或设备出错' })
          exit()
          return
        }

        if (rescode[ret] === 'success') {
          process.send({ rescode: 0, ret, message: '查询成功' })

          const transOutBuf = bufferTrim
            .trimEnd(Buffer.from(cardAndQrcode.transOutBuf))
            .toString()

          process.send({ rescode: 2, ret, transOutBuf })

          const res = isJSON(transOutBuf) ? JSON.parse(transOutBuf) : {}

          console.log('寻卡结果', res)
          process.send({ rescode: 2, msg: '寻卡结果', data: res })

          let id

          switch (res.cardType) {
            case '1': // 社保卡
              id = getSBCard()
              break
            case '2': // 身份证
              id = getSFZCard()
              break
            case '187': // 扫码
              id = getQRcode(res)
              break
          }

          console.log('id', id)
        }

        setTimeout(() => {
          search()
        }, 500)
      } catch (e) {
        process.send(e)
      }
    }

    function getSBCard () {
      // console.log("sb");
      const cardInfo = new CardInfo()
      const ret0 = program.Sodo_SB_Process(cardInfo.ref())
      console.log('[ ret0 ]', ret0)

      console.log('cardInfo', cardInfo, Buffer.from(cardInfo.recvBuf).toString())

      const res = Buffer.alloc(512)
      const inp = Buffer.alloc(512)

      const ret = program.Sodo_SB_Psam_Process_GetAllInfo(res.ref(), inp.ref(), 4)

      if (rescode[ret] !== 'success') return

      const data = bufferTrim
        .trimEnd(Buffer.from(res))
        .toString()
        .trim()
        .split('|')

      // 返回:卡片发行机构代码|社保卡卡号|卡片识别码|卡复位的信息|卡片版本|发行日期|有效日期
      const params = {
        qrcode_info: data[2], // 必填,社保卡使用卡识别码，电子社保卡使用二维码原始字符串, (应该扫码或者读卡机自动获取)
        card_type: '01', // 社保卡01 , 二维码04
        card_number: data[1], // 9位社保卡号（当介质类型为社保卡时必填）
        card_version: data[4], // 卡规范版本
        publish_date: data[5], // 发卡日期
        expiry_date: data[6], // 卡有效期
        card_rest_info: data[3] // 卡复位信息
      }

      console.log('[ params ]', params)
      process.send({
        rescode: 1,
        msg: '社保卡',
        data: params,
        cardInfo: bufferTrim.trimEnd(Buffer.from(cardInfo.recvBuf)).toString()
      })
      return params
    }

    function getSFZCard () {
      const cardInfo = new SfzInfo()
      cardInfo.cmdOp1 = 0x03
      cardInfo.cmdOp2 = 0x00
      const ret = program['_Sodo_Sfz_Process@4'](cardInfo.ref())
      console.log('ret', ret)

      const idStr = Buffer.from(cardInfo.recvBuf)
        .slice(7, 263)
        .toString('ucs2')

      if (
        !idStr
          .slice(61, 79)
          .trim()
          .replace(/\0/g, '').length
      ) { return }
      // if (!bufferTrim.trim()) return;
      console.log('%c [ idStr ]-109', idStr)

      const res = {
        name: idStr.slice(0, 15).trim(),
        sex: getSex(idStr.slice(15, 16)),
        nation: getNation(idStr.slice(16, 18)),
        idNum: idStr.slice(61, 79).trim(),
        address: idStr.slice(26, 61).trim(),
        begin: idStr.slice(94, 102).trim(),
        end: idStr.slice(102, 110).trim()
      }
      process.send({ rescode: 1, msg: '身份证', res })
      console.log('%c [ res ]-112', res)
    }

    function getQRcode (res) {
      const qrcode = Buffer.from(res.ID, 'base64').toString()

      const params = {
        qrcode_info: qrcode,
        card_type: '04'
      }

      console.log('params', params)
      process.send({ rescode: 1, msg: '扫码', data: params })
      return params
    }

    function isJSON (str) {
      try {
        JSON.parse(str)
      } catch (e) {
        return false
      }
      return true
    }

    function getSex (code) {
      switch (parseInt(code)) {
        case 0:
          return '未知的性别'
        case 1:
          return '男'
        case 2:
          return '女'
        case 9:
          return '未说明的性别'
      }
      return '未定义的性别'
    }

    function getNation (code) {
      switch (parseInt(code)) {
        case 1:
          return '汉'
        case 2:
          return '蒙古'
        case 3:
          return '回'
        case 4:
          return '藏'
        case 5:
          return '维吾尔'
        case 6:
          return '苗'
        case 7:
          return '彝'
        case 8:
          return '壮'
        case 9:
          return '布依'
        case 10:
          return '朝鲜'
        case 11:
          return '满'
        case 12:
          return '侗'
        case 13:
          return '瑶'
        case 14:
          return '白'
        case 15:
          return '土家'
        case 16:
          return '哈尼'
        case 17:
          return '哈萨克'
        case 18:
          return '傣'
        case 19:
          return '黎'
        case 20:
          return '傈僳'
        case 21:
          return '佤'
        case 22:
          return '畲'
        case 23:
          return '高山'
        case 24:
          return '拉祜'
        case 25:
          return '水'
        case 26:
          return '东乡'
        case 27:
          return '纳西'
        case 28:
          return '景颇'
        case 29:
          return '柯尔克孜'
        case 30:
          return '土'
        case 31:
          return '达斡尔'
        case 32:
          return '仫佬'
        case 33:
          return '羌'
        case 34:
          return '布朗'
        case 35:
          return '撒拉'
        case 36:
          return '毛难'
        case 37:
          return '仡佬'
        case 38:
          return '锡伯'
        case 39:
          return '阿昌'
        case 40:
          return '普米'
        case 41:
          return '塔吉克'
        case 42:
          return '怒'
        case 43:
          return '乌孜别克'
        case 44:
          return '俄罗斯'
        case 45:
          return '鄂温克'
        case 46:
          return '崩龙'
        case 47:
          return '保安'
        case 48:
          return '裕固'
        case 49:
          return '京'
        case 50:
          return '塔塔尔'
        case 51:
          return '独龙'
        case 52:
          return '鄂伦春'
        case 53:
          return '赫哲'
        case 54:
          return '门巴'
        case 55:
          return '珞巴'
        case 56:
          return '基诺'
      }
    }

    function exit () {
      process.kill(process.pid)
      process.exit(0)
    }

    return new Promise((resolve, reject) => {
      program.Sodo_InitSerialPort(parseInt(port), 115200)
      console.log('已执行初始化串口', port)

      const ret = program.Sodo_Start()

      if (rescode[ret] !== 'success') {
        console.log('打开串口失败')
        process.send({ rescode: 0, msg: '打开串口失败' })

        exit()
      } else {
        process.send({ rescode: 0, ret })
        try {
          search()
        } catch (e) {
          process.send(e)
        }
      }
    })
  } catch (e) {
    process.send({ rescode: 0, e })
  }
})
