const { parentPort } = require("worker_threads");
const koffi = require("koffi");
const path = require("path");
const iconv = require("iconv-lite");

// 定义结构体 (使用原始字节数组，避免对齐问题，手动解析)
const IDCardData = koffi.struct("IDCardData", {
  raw: koffi.array("uint8", 1024), // 分配足够大的空间
});

let lib = null;
let apiCache = null;
let running = false;

// 解码字符串 (GBK)
function decodeString(buffer) {
  // 这里的 buffer 是 uint8 数组 或 Buffer
  const buf = Buffer.isBuffer(buffer) ? buffer : Buffer.from(buffer);

  // 找到第一个 null 字节 (0x00) 的位置
  let nullIndex = -1;
  for (let i = 0; i < buf.length; i++) {
    if (buf[i] === 0) {
      nullIndex = i;
      break;
    }
  }
  const validBuf = nullIndex !== -1 ? buf.slice(0, nullIndex) : buf;
  return iconv.decode(validBuf, "gbk").trim();
} // 加载 DLL
function loadDll() {
  if (apiCache) return apiCache;
  try {
    const fs = require("fs");
    const dllNames = ["Syn_IDCardRead.dll", "SynIDCardRead.dll"];

    // 确定 DLL 目录：优先检查生产环境 resources/xzx，否则使用开发环境 resources/xzx
    let dllDir = path.join(process.cwd(), "resources", "xzx");
    if (process.resourcesPath) {
      const prodDir = path.join(process.resourcesPath, "xzx");
      if (fs.existsSync(prodDir)) {
        dllDir = prodDir;
      }
    }

    let dllPath = null;
    for (const name of dllNames) {
      const p = path.join(dllDir, name);
      if (fs.existsSync(p)) {
        dllPath = p;
        break;
      }
    }

    if (!dllPath) {
      throw new Error(`DLL not found in ${dllDir}`);
    }

    parentPort.postMessage({
      type: "log",
      payload: `Loading DLL from: ${dllPath}`,
    });
    lib = koffi.load(dllPath);

    // 尝试使用 stdcall 约定，这对于 Windows 32位 DLL 很常见
    // koffi 2.x 版本中，stdcall 约定需要在函数名前加 __stdcall
    // 如果字符串解析失败，可以尝试使用 lib.stdcall() 方法

    // 辅助函数：尝试加载函数，支持原名和修饰名
    const loadFunc = (name, alias, ret, args) => {
      try {
        return lib.stdcall(name, ret, args);
      } catch (e) {
        try {
          return lib.stdcall(alias, ret, args);
        } catch (e2) {
          throw new Error(
            `Cannot find function '${name}' or '${alias}' in DLL`
          );
        }
      }
    };

    try {
      apiCache = {
        Syn_OpenPort: loadFunc("Syn_OpenPort", "_Syn_OpenPort@4", "int", [
          "int",
        ]),
        Syn_ClosePort: loadFunc("Syn_ClosePort", "_Syn_ClosePort@4", "int", [
          "int",
        ]),
        Syn_StartFindIDCard: loadFunc(
          "Syn_StartFindIDCard",
          "_Syn_StartFindIDCard@12",
          "int",
          ["int", "uint8*", "int"]
        ),
        Syn_SelectIDCard: loadFunc(
          "Syn_SelectIDCard",
          "_Syn_SelectIDCard@12",
          "int",
          ["int", "uint8*", "int"]
        ),
        Syn_ReadMsg: loadFunc("Syn_ReadMsg", "_Syn_ReadMsg@12", "int", [
          "int",
          "int",
          koffi.out(koffi.pointer(IDCardData)),
        ]),
      };
      return apiCache;
    } catch (e) {
      throw e;
    }
  } catch (err) {
    parentPort.postMessage({
      type: "error",
      payload: `Failed to load DLL: ${err.message}`,
    });
    return null;
  }
}

async function startListen() {
  if (running) return;
  running = true;

  const api = loadDll();
  if (!api) {
    running = false;
    return;
  }

  try {
    // 尝试打开端口，优先尝试 1001 (USB)
    let port = 1001;
    let openRes = api.Syn_OpenPort(port);

    if (openRes !== 0) {
      // 如果 1001 失败，尝试 1001-1016
      for (let p = 1002; p <= 1016; p++) {
        if (api.Syn_OpenPort(p) === 0) {
          port = p;
          openRes = 0;
          break;
        }
      }
    }

    if (openRes !== 0) {
      parentPort.postMessage({
        type: "error",
        payload: `Open port failed (tried 1001-1016)`,
      });
      running = false;
      return;
    }

    parentPort.postMessage({
      type: "log",
      payload: `Port ${port} opened successfully`,
    });

    const iin = Buffer.alloc(4);
    const sn = Buffer.alloc(8);
    // IDCardData 结构体大小计算: 32+6+20+18+72+38+32+18+18+38+255 = 547 字节
    // koffi 会自动处理结构体内存分配

    while (running) {
      // 寻卡
      api.Syn_StartFindIDCard(port, iin, 0);
      // 选卡
      api.Syn_SelectIDCard(port, sn, 0);

      // 读卡
      const data = {}; // koffi 输出对象
      const ret = api.Syn_ReadMsg(port, 0, data);

      if (ret === 0 && data && data.raw) {
        const rawBuf = Buffer.from(data.raw);

        // 调试：打印前 64 字节 Hex
        // parentPort.postMessage({
        //   type: "log",
        //   payload: `Raw Hex (First 64): ${rawBuf.slice(0, 64).toString("hex")}`,
        // });

        // 手动切片解析 (修正后的偏移)
        // Name: 0-32 (32)
        // Sex: 32-36 (4)
        // Nation: 36-42 (6)
        // Born: 42-60 (18)
        // Address: 60-132 (72)
        // IDCardNo: 132-170 (38)
        // GrantDept: 170-202 (32)
        // UserLifeBegin: 202-220 (18)
        // UserLifeEnd: 220-238 (18)
        // PhotoFileName: 276-531 (255)

        const payload = {
          name: decodeString(rawBuf.slice(0, 32)),
          sex: decodeString(rawBuf.slice(32, 36)),
          nation: decodeString(rawBuf.slice(36, 42)),
          born: decodeString(rawBuf.slice(42, 60)),
          address: decodeString(rawBuf.slice(60, 132)),
          id_card_no: decodeString(rawBuf.slice(132, 170)),
          grant_dept: decodeString(rawBuf.slice(170, 202)),
          life_begin: decodeString(rawBuf.slice(202, 220)),
          life_end: decodeString(rawBuf.slice(220, 238)),
          photo_path: decodeString(rawBuf.slice(276, 531)),
        };

        parentPort.postMessage({
          type: "log",
          payload: `Read IDCard success: ${payload.name} ${payload.id_card_no}`,
        });
        // 打印完整 payload 以便调试
        parentPort.postMessage({
          type: "log",
          payload: `Full Payload: ${JSON.stringify(payload)}`,
        });
        parentPort.postMessage({ type: "data", payload });

        // 读到卡后暂停一下，避免重复读取太快
        await new Promise((r) => setTimeout(r, 500));
      } else {
        // 没读到卡，稍微等待
        await new Promise((r) => setTimeout(r, 150));
      }
    }

    api.Syn_ClosePort(port);
  } catch (err) {
    parentPort.postMessage({
      type: "error",
      payload: `Worker error: ${err.message}`,
    });
    running = false;
  }
}

parentPort.on("message", (msg) => {
  if (msg === "start") {
    startListen();
  } else if (msg === "stop") {
    running = false;
  }
});
