const logger = require("../lib/logger");
const split = require("split");
const fs = require("fs");
const { spawn, spawnSync } = require("child_process");

const isVerbose = process.env.NRC_GPIO_VERBOSE === "1";

// Bookworm兼容性处理
let pwm, rpio, gpio;
let useGpiomem = false;

// 检测系统版本和GPIO库可用性
function detectGpioLibrary() {
  try {
    // 检测是否为Bookworm
    const osRelease = fs.readFileSync("/etc/os-release", "utf8");
    const isBookworm = osRelease.includes("bookworm") || osRelease.includes("trixie");

    if (isBookworm) {
      logger.info("检测到Bookworm系统，尝试使用gpiomem接口");
      useGpiomem = true;
    }

    const pidFile = "/var/run/pigpio.pid";
    const canUsePigpio = () => {
      if (!fs.existsSync(pidFile)) return true;
      try {
        const pid = parseInt(fs.readFileSync(pidFile, "utf8"), 10);
        if (pid && pid > 0) {
          process.kill(pid, 0);
          logger.warn(`检测到 pigpio 进程(${pid})占用，跳过 pigpio`);
          return false;
        }
      } catch (e) {
        // 进程不存在，尝试清理残留 pid 文件
      }

      try {
        fs.unlinkSync(pidFile);
        logger.warn("检测到残留 pigpio.pid，已清理");
      } catch (e) {}
      return true;
    };

    // 尝试加载GPIO库 (所有系统都优先使用pigpio)
    const allowPigpio = canUsePigpio();
    if (allowPigpio) {
      try {
        const pigpio = require("pigpio");
        rpio = pigpio;
        logger.info("使用pigpio库");
      } catch (e) {
        logger.warn("pigpio不可用，尝试rpio...");
        try {
          rpio = require("rpio");
          if (useGpiomem) {
            rpio.init({ mapping: "gpio", gpiomem: true });
          } else {
            rpio.init({ mapping: "gpio" });
          }
        } catch (err) {
          logger.error("rpio不可用: " + err.message);
          rpio = null;
        }
      }
    } else {
      logger.warn("pigpio被占用，尝试rpio...");
      try {
        rpio = require("rpio");
        if (useGpiomem) {
          rpio.init({ mapping: "gpio", gpiomem: true });
        } else {
          rpio.init({ mapping: "gpio" });
        }
      } catch (err) {
        logger.error("rpio不可用: " + err.message);
        rpio = null;
      }
    }

    // 使用pigpio的PWM功能替代rpio-pwm
    try {
      if (rpio && typeof rpio.Gpio === "function") {
        // 创建基于pigpio的PWM接口
        pwm = {
          create_pwm: function (pin) {
            return {
              pin: pin,
              set_width: function (width) {
                // pigpio PWM实现
                const dutyCycle = Math.round((width / stepNum) * 1000000); // 转换为微秒
                rpio.hardwarePWM(this.pin, refresh, dutyCycle);
              },
              release: function () {
                rpio.hardwarePWM(this.pin, 0, 0);
              },
            };
          },
          host_is_model_pi4: function () {
            return false; // 简化处理
          },
        };
        logger.info("使用pigpio硬件PWM功能");
      } else {
        throw new Error("pigpio不可用");
      }
    } catch (e) {
      logger.error("PWM功能初始化失败: " + e.message);
      logger.warn("PWM功能不可用，只有GPIO开关功能可用");
    }
  } catch (error) {
    logger.error("GPIO库初始化失败: " + error.message);
    throw error;
  }
}

// 初始化GPIO库
detectGpioLibrary();

const status = {};

let encoderTimer;
let encoderPins;
let encoderListener;
let encoderPollTimer;
let encoderLastState = 0;
let encoderIntervalCount = 0;
let encoderTotalCount = 0;
let encoderLastDir = 0;
let encoderConfig = null;
let gpiomonProcess;
let gpiodState = { a: 0, b: 0 };
let gpiodSettings = null;

const encoderTransitions = {
  0: { 1: 1, 2: -1 },
  1: { 3: 1, 0: -1 },
  3: { 2: 1, 1: -1 },
  2: { 0: 1, 3: -1 },
};

let refresh = 50, // 频率
  stepNum = 1000, // 精度
  pwmPinMap = {},
  switchPinList = [],
  pwmCh;

const cycleTimeUs = (1000 / refresh) * 1000, // 周期时长 20000us
  stepTimeUs = cycleTimeUs / stepNum; // 单步时长  40us

/**
 * 初始化PWM通道（仅用于非pigpio场景）
 * @param {Number} refresh PWM 频率
 * @returns undefined
 */
const initPwmCh = () => {
  if (pwmCh) return;

  // pigpio场景不需要初始化pwmCh
  if (rpio && typeof rpio.Gpio === "function") return;

  if (!pwm) {
    logger.warn("PWM库不可用，PWM功能将被禁用");
    return;
  }

  if (typeof pwm.create_dma_channel === "function") {
    try {
      pwmCh = pwm;
      logger.info("PWM通道初始化成功（兼容模式）");
    } catch (error) {
      logger.error("PWM通道初始化失败: " + error.message);
      pwmCh = null;
    }
  } else {
    logger.warn("PWM库不支持DMA通道，跳过PWM初始化");
  }
};

function initPin(pinBoardCode = 12) {
  // 优先使用pigpio（支持任意GPIO的servoWrite）
  if (rpio && typeof rpio.Gpio === "function") {
    return new rpio.Gpio(pinBoardCode, { mode: rpio.OUTPUT });
  }

  if (!pwmCh) {
    initPwmCh();
  }

  return pwmCh ? pwmCh.create_pwm(pinBoardCode) : null;
}

/**
 * 设置空占比（兼容非pigpio场景）
 * @param {Number} pin
 * @param {Number} round 空占比 0 ～ 100
 */
function setRound(pin, round) {
  if (pin && typeof pin.set_width === "function") {
    pin.set_width((round / 100) * stepNum);
  }
}

// 计算舵机/电调脉宽（微秒）
function calcPulseWidth(v) {
  // v范围通常是[-1,1]或[-2,2]
  const pulse = Math.round(1500 + v * 500); // 1500us为中位
  return Math.min(2500, Math.max(500, pulse));
}

function changePwmPin(pin, v) {
  pin = parseInt(pin);
  v = Number(v);
  if (isVerbose) {
    logger.info(`Change PWM channel: ${pin}, value: ${v}`);
  }
  status[pin] = v;

  if (!pwmPinMap[pin]) {
    pwmPinMap[pin] = initPin(pin);
  }

  const pwmPin = pwmPinMap[pin];
  if (!pwmPin) {
    logger.warn(`PWM通道 ${pin} 未初始化`);
    return;
  }

  // pigpio场景：使用servoWrite（支持任意GPIO）
  if (typeof pwmPin.servoWrite === "function") {
    const pulseWidth = calcPulseWidth(v);
    pwmPin.servoWrite(pulseWidth);
    return;
  }

  // 兼容旧PWM接口
  if (typeof pwmPin.set_width === "function") {
    const dutyCycle = v * 2.5 + 7.5; // 7.5% - 15%
    pwmPin.set_width((dutyCycle / 100) * stepNum);
    return;
  }

  logger.warn(`PWM通道 ${pin} 不支持servoWrite/set_width`);
}

function stopEncoder() {
  if (encoderTimer) {
    clearInterval(encoderTimer);
    encoderTimer = null;
  }
  if (encoderPollTimer) {
    clearInterval(encoderPollTimer);
    encoderPollTimer = null;
  }
  if (gpiomonProcess) {
    try {
      gpiomonProcess.kill("SIGTERM");
    } catch (e) {}
    gpiomonProcess = null;
  }
  if (encoderPins && encoderPins.a && encoderPins.a.disableAlert) {
    try {
      encoderPins.a.disableAlert();
    } catch (e) {}
  }
  if (encoderPins && encoderPins.b && encoderPins.b.disableAlert) {
    try {
      encoderPins.b.disableAlert();
    } catch (e) {}
  }
  if (encoderListener && rpio && typeof rpio.removeListener === "function") {
    try {
      rpio.removeListener("change", encoderListener);
    } catch (e) {}
  }
  encoderPins = null;
  encoderListener = null;
  encoderConfig = null;
  gpiodSettings = null;
  gpiodState = { a: 0, b: 0 };
  encoderIntervalCount = 0;
  encoderTotalCount = 0;
  encoderLastDir = 0;
}

const resolveGpiodSettings = (config = {}) => {
  const backend = String(
    config.gpioBackend || config.backend || process.env.NRC_GPIO_BACKEND || ""
  ).toLowerCase();
  if (backend !== "gpiod") return null;
  const chip = String(config.gpiodChip || config.gpioChip || "gpiochip0");
  const lineA = Number(config.gpiodLineA ?? config.lineA);
  const lineB = Number(config.gpiodLineB ?? config.lineB);
  if (!Number.isFinite(lineA) || !Number.isFinite(lineB)) {
    logger.error("gpiod 启动失败：gpiodLineA/gpiodLineB 无效");
    return null;
  }
  const bias = config.gpiodBias || config.bias || "as-is";
  const activeLow = !!(config.gpiodActiveLow ?? config.activeLow);
  return { chip, lineA, lineB, bias, activeLow };
};

const readGpiodState = (settings) => {
  if (!settings) return null;
  const args = [];
  if (settings.activeLow) args.push("-l");
  if (settings.bias) args.push(`-B=${settings.bias}`);
  args.push(settings.chip, String(settings.lineA), String(settings.lineB));
  const result = spawnSync("gpioget", args, { encoding: "utf8" });
  if (result.status !== 0) {
    logger.error(`gpioget 失败: ${result.stderr || result.stdout || "unknown"}`);
    return null;
  }
  const parts = String(result.stdout || "").trim().split(/\s+/);
  if (parts.length < 2) return null;
  return {
    a: Number(parts[0]) ? 1 : 0,
    b: Number(parts[1]) ? 1 : 0,
  };
};

function startEncoder(config = {}) {
  stopEncoder();
  const gpiodConfig = resolveGpiodSettings(config);
  const pinA = gpiodConfig ? gpiodConfig.lineA : Number(config.pinA);
  const pinB = gpiodConfig ? gpiodConfig.lineB : Number(config.pinB);
  if (!Number.isFinite(pinA) || !Number.isFinite(pinB)) {
    logger.error("Encoder 启动失败：pinA/pinB 无效");
    return;
  }

  const mode = ["x1", "x2", "x4"].includes(config.mode) ? config.mode : "x4";
  const modeFactor = mode === "x1" ? 1 : mode === "x2" ? 2 : 4;
  const ppr = Math.max(1, Number(config.ppr) || 0);
  const countsPerRev = ppr * modeFactor;
  const intervalMs = Math.max(50, Number(config.intervalMs) || 1000);
  const glitchUs = Math.max(0, Number(config.glitchUs) || 0);
  const invert = !!config.invert;
  const pollIntervalMs = Math.max(1, Number(config.pollIntervalMs) || 2);
  const forcePolling = !!config.forcePolling;

  encoderConfig = {
    pinA,
    pinB,
    mode,
    modeFactor,
    countsPerRev,
    intervalMs,
    glitchUs,
    invert,
  };

  const shouldCount = (gpio, level) => {
    if (mode === "x4") return true;
    if (mode === "x2") return gpio === pinA;
    return gpio === pinA && level === 1;
  };

  const shouldCountByState = (lastState, state) => {
    if (mode === "x4") return true;
    const lastA = (lastState >> 1) & 1;
    const currA = (state >> 1) & 1;
    if (mode === "x2") return lastA !== currA;
    return lastA === 0 && currA === 1;
  };

  if (gpiodConfig) {
    gpiodSettings = gpiodConfig;
    const initState = readGpiodState(gpiodSettings);
    if (!initState) {
      logger.error("gpiod 初始化读取失败，无法启动编码器");
      return;
    }
    gpiodState = initState;
    encoderLastState = (gpiodState.a << 1) | gpiodState.b;

    if (forcePolling) {
      encoderPollTimer = setInterval(() => {
        const stateNow = readGpiodState(gpiodSettings);
        if (!stateNow) return;
        const state = (stateNow.a << 1) | stateNow.b;
        const step = encoderTransitions[encoderLastState]?.[state] || 0;
        if (step !== 0 && shouldCountByState(encoderLastState, state)) {
          const delta = invert ? -step : step;
          encoderIntervalCount += delta;
          encoderTotalCount += delta;
          encoderLastDir = delta;
        }
        gpiodState = stateNow;
        encoderLastState = state;
      }, pollIntervalMs);
    } else {
      const args = [];
      if (gpiodSettings.activeLow) args.push("-l");
      if (gpiodSettings.bias) args.push(`-B=${gpiodSettings.bias}`);
      args.push("-b", "-F", "%o %e", gpiodSettings.chip);
      args.push(String(gpiodSettings.lineA), String(gpiodSettings.lineB));
      gpiomonProcess = spawn("gpiomon", args, { stdio: ["ignore", "pipe", "pipe"] });

      gpiomonProcess.stdout.on("data", (data) => {
        const lines = data
          .toString()
          .split("\n")
          .map((line) => line.trim())
          .filter(Boolean);

        lines.forEach((line) => {
          const [offsetText, eventText] = line.split(/\s+/);
          const offset = Number(offsetText);
          const event = Number(eventText);
          if (!Number.isFinite(offset) || !Number.isFinite(event)) return;
          if (offset !== gpiodSettings.lineA && offset !== gpiodSettings.lineB) return;

          const level = event === 1 ? 1 : 0;
          if (offset === gpiodSettings.lineA) {
            gpiodState.a = level;
          } else {
            gpiodState.b = level;
          }

          const state = (gpiodState.a << 1) | gpiodState.b;
          const step = encoderTransitions[encoderLastState]?.[state] || 0;
          if (step !== 0 && shouldCount(offset, level)) {
            const delta = invert ? -step : step;
            encoderIntervalCount += delta;
            encoderTotalCount += delta;
            encoderLastDir = delta;
          }
          encoderLastState = state;
        });
      });

      gpiomonProcess.stderr.on("data", (data) => {
        logger.error(`gpiomon 错误: ${data}`);
      });

      gpiomonProcess.on("exit", (code) => {
        if (code !== 0) {
          logger.warn(`gpiomon 退出，code=${code}`);
        }
      });
    }
  } else if (typeof rpio.Gpio === "function") {
    encoderPins = {
      a: new rpio.Gpio(pinA, {
        mode: rpio.INPUT,
        alert: !forcePolling,
        edge: rpio.EITHER_EDGE,
      }),
      b: new rpio.Gpio(pinB, {
        mode: rpio.INPUT,
        alert: !forcePolling,
        edge: rpio.EITHER_EDGE,
      }),
    };

    if (glitchUs > 0 && typeof encoderPins.a.glitchFilter === "function") {
      encoderPins.a.glitchFilter(glitchUs);
      encoderPins.b.glitchFilter(glitchUs);
    }

    const readState = () =>
      (encoderPins.a.digitalRead() << 1) | encoderPins.b.digitalRead();

    encoderLastState = readState();

    if (forcePolling) {
      encoderPollTimer = setInterval(() => {
        const state = readState();
        const step = encoderTransitions[encoderLastState]?.[state] || 0;
        if (step !== 0 && shouldCountByState(encoderLastState, state)) {
          const delta = invert ? -step : step;
          encoderIntervalCount += delta;
          encoderTotalCount += delta;
          encoderLastDir = delta;
        }
        encoderLastState = state;
      }, pollIntervalMs);
    } else {
      const handleEdge = (gpio, level) => {
        const state = readState();
        const step = encoderTransitions[encoderLastState]?.[state] || 0;
        if (step !== 0 && shouldCount(gpio, level)) {
          const delta = invert ? -step : step;
          encoderIntervalCount += delta;
          encoderTotalCount += delta;
          encoderLastDir = delta;
        }
        encoderLastState = state;
      };

      encoderPins.a.on("alert", (level) => handleEdge(pinA, level));
      encoderPins.b.on("alert", (level) => handleEdge(pinB, level));
    }
  } else if (rpio && typeof rpio.on === "function") {
    if (typeof rpio.setup === "function") {
      rpio.setup(pinA, rpio.INPUT, rpio.EDGE_BOTH);
      rpio.setup(pinB, rpio.INPUT, rpio.EDGE_BOTH);
    }

    const readState = () => {
      const a = rpio.read(pinA);
      const b = rpio.read(pinB);
      return (a << 1) | b;
    };

    encoderLastState = readState();

    if (useGpiomem || forcePolling) {
      encoderPollTimer = setInterval(() => {
        const state = readState();
        const step = encoderTransitions[encoderLastState]?.[state] || 0;
        if (step !== 0 && shouldCountByState(encoderLastState, state)) {
          const delta = invert ? -step : step;
          encoderIntervalCount += delta;
          encoderTotalCount += delta;
          encoderLastDir = delta;
        }
        encoderLastState = state;
      }, pollIntervalMs);
    } else {
      encoderListener = (channel, value) => {
        if (channel !== pinA && channel !== pinB) return;
        const state = readState();
        const step = encoderTransitions[encoderLastState]?.[state] || 0;
        if (step !== 0 && shouldCount(channel, value)) {
          const delta = invert ? -step : step;
          encoderIntervalCount += delta;
          encoderTotalCount += delta;
          encoderLastDir = delta;
        }
        encoderLastState = state;
      };

      rpio.on("change", encoderListener);
    }
  } else {
    logger.warn("Encoder 启动失败：GPIO 事件监听不可用");
    return;
  }

  encoderTimer = setInterval(() => {
    const count = encoderIntervalCount;
    encoderIntervalCount = 0;
    const intervalSec = intervalMs / 1000;
    const revolutions = encoderConfig.countsPerRev
      ? count / encoderConfig.countsPerRev
      : 0;
    const rpm = intervalSec > 0 ? (revolutions / intervalSec) * 60 : 0;
    const dir = encoderLastDir >= 0 ? "forward" : "reverse";
    const payload = {
      pinA,
      pinB,
      count,
      total: encoderTotalCount,
      rpm,
      dir,
    };
    process.stdout.write(`encoder|${JSON.stringify(payload)}\n`);
  }, intervalMs);

  logger.info(
    `Encoder 启动: A=${pinA}, B=${pinB}, PPR=${ppr}, mode=${mode}, interval=${intervalMs}ms`
  );
}

function listen(pin) {
  pin = parseInt(pin);
  try {
    if (typeof rpio.Gpio === "function") {
      // 使用pigpio的事件监听
      const gpio = new rpio.Gpio(pin, {
        mode: rpio.INPUT,
        alert: true,
        edge: rpio.EITHER_EDGE,
      });

      gpio.on("alert", (level, tick) => {
        logger.info(`GPIO ${pin} change: ${level}`);
        process.stdout.write(
          "gpio-change|" + JSON.stringify({ pin: pin, value: level })
        );
      });

      logger.info(`GPIO ${pin} 监听已启用 (pigpio)`);
    } else if (rpio && typeof rpio.on === "function") {
      // 使用rpio的事件监听
      rpio.on("change", function (channel, value) {
        if (channel === pin) {
          logger.info(`GPIO channel change: ${channel}, value: ${value}`);
          process.stdout.write(
            "gpio-change|" + JSON.stringify({ pin: pin, value })
          );
        }
      });
      rpio.setup(pin, rpio.INPUT, rpio.EDGE_BOTH);
      logger.info(`GPIO ${pin} 监听已启用 (rpio)`);
    } else {
      // 使用polling方式作为备选方案
      logger.warn(`GPIO事件监听不可用，使用polling模式监听引脚 ${pin}`);
      if (typeof rpio.setup === "function") {
        rpio.setup(pin, rpio.INPUT);
      }
      pollPin(pin, 100); // 100ms轮询间隔
    }
  } catch (error) {
    logger.error(`GPIO监听初始化失败 (pin ${pin}): ${error.message}`);
  }
}

// 轮询GPIO状态变化 (Bookworm备选方案)
function pollPin(pin, interval) {
  let lastValue = rpio.read(pin);

  setInterval(() => {
    try {
      const currentValue = rpio.read(pin);
      if (currentValue !== lastValue) {
        lastValue = currentValue;
        logger.info(`GPIO polling change: ${pin}, value: ${currentValue}`);
        process.stdout.write(
          "gpio-change|" + JSON.stringify({ pin: pin, value: currentValue })
        );
      }
    } catch (error) {
      logger.error(`GPIO轮询读取失败 (pin ${pin}): ${error.message}`);
    }
  }, interval);
}

function readPin(pinBoardCode) {
  pinBoardCode = parseInt(pinBoardCode);

  try {
    if (typeof rpio.Gpio === "function") {
      // 使用pigpio
      const gpio = new rpio.Gpio(pinBoardCode, {
        mode: rpio.INPUT,
      });
      const value = gpio.readSync();
      process.stdout.write(
        "gpio-change|" + JSON.stringify({ pin: pinBoardCode, value })
      );
    } else if (rpio && typeof rpio.setup === "function") {
      // 使用rpio
      rpio.setup(pinBoardCode, rpio.INPUT);

      if (useGpiomem && typeof rpio.read === "function") {
        // 同步读取方式
        const value = rpio.read(pinBoardCode);
        process.stdout.write(
          "gpio-change|" + JSON.stringify({ pin: pinBoardCode, value })
        );
      } else {
        // 异步读取方式
        rpio.read(pinBoardCode, function (err, value) {
          if (err) {
            logger.error(`Read pin ${pinBoardCode} error: ${err}`);
          } else {
            process.stdout.write(
              "gpio-change|" + JSON.stringify({ pin: pinBoardCode, value })
            );
          }
        });
      }
    } else {
      logger.error(`GPIO库不可用，无法读取引脚 ${pinBoardCode}`);
    }
  } catch (error) {
    logger.error(`Read pin ${pinBoardCode} error: ${error}`);
  }
}

function changeSwitchPin(pinBoardCode, enabled) {
  pinBoardCode = parseInt(pinBoardCode);
  enabled = JSON.parse(enabled);
  if (isVerbose) {
    logger.info(`Change Switch channel: ${pinBoardCode}, value: ${enabled}`);
  }
  status[pinBoardCode] = enabled;

  if (!switchPinList.includes(pinBoardCode)) {
    switchPinList.push(pinBoardCode);
  }

  try {
    if (typeof rpio.Gpio === "function") {
      // 使用pigpio（数字输出）
      if (!rpio.pinInstances) rpio.pinInstances = {};
      let gpio = rpio.pinInstances[pinBoardCode];
      if (!gpio) {
        gpio = new rpio.Gpio(pinBoardCode, { mode: rpio.OUTPUT });
        rpio.pinInstances[pinBoardCode] = gpio;
      }
      gpio.digitalWrite(enabled ? 1 : 0);
    } else {
      // 使用rpio
      if (enabled) {
        if (useGpiomem) {
          rpio.write(pinBoardCode, rpio.HIGH);
        } else {
          rpio.open(pinBoardCode, rpio.OUTPUT, rpio.HIGH);
        }
      } else {
        if (useGpiomem) {
          rpio.write(pinBoardCode, rpio.LOW);
        } else {
          rpio.open(pinBoardCode, rpio.OUTPUT, rpio.LOW);
        }
      }
    }
  } catch (error) {
    logger.error(`GPIO开关控制失败 (pin ${pinBoardCode}): ${error.message}`);
  }
}

const closeChannel = function () {
  logger.info("Close GPIO channel");

  // 清理PWM通道
  Object.keys(pwmPinMap).forEach((pin) => {
    try {
      changePwmPin(pin, 0);
      if (pwmPinMap[pin] && typeof pwmPinMap[pin].release === "function") {
        pwmPinMap[pin].release();
      }
    } catch (error) {
      logger.error(`PWM通道关闭失败 (pin ${pin}): ${error.message}`);
    }
  });

  // 清理GPIO开关
  switchPinList.forEach((pin) => {
    try {
      changeSwitchPin(pin, false);
      if (rpio) {
        if (typeof rpio.Gpio === "function") {
          // pigpio的清理
          // 注意：pigpio的Gpio实例会在进程退出时自动清理
        } else if (typeof rpio.close === "function") {
          // rpio的清理
          rpio.close(pin);
        }
      }
    } catch (error) {
      logger.error(`GPIO关闭失败 (pin ${pin}): ${error.message}`);
    }
  });

  // 清理PWM通道
  if (rpio && typeof rpio.hardwarePWM === "function") {
    try {
      // 停止所有PWM
      Object.keys(pwmPinMap).forEach((pin) => {
        rpio.hardwarePWM(parseInt(pin), 0, 0);
      });
    } catch (error) {
      logger.error(`PWM通道关闭失败: ${error.message}`);
    }
  }

  pwmPinMap = {};
  switchPinList = [];
  pwmCh = null;
};

if (rpio && typeof rpio.on === "function") {
  rpio.on("change", (pin, value) => {
    logger.info(`GPIO ${pin} changed to ${value}`);
    process.stdout.write("gpio-change|" + JSON.stringify({ pin, value }));
  });
} else {
  logger.info("GPIO事件监听不可用（pigpio模式不支持rpio.on）");
}

process.stdin.pipe(split()).on("data", (data) => {
  if (process.env.NRC_GPIO_VERBOSE === "1") {
    logger.info(`Receive data: ${data}\n`);
  }
  const text = data.toString().trim();
  if (!text) return;
  const [type, ...rest] = text.split(" ");
  const pin = rest[0];
  const v = rest[1];
  try {
    switch (type) {
      case "listen":
        listen(pin);
        break;
      case "pwm":
        changePwmPin(pin, v);
        break;
      case "sw":
        changeSwitchPin(pin, v);
        break;
      case "encoder": {
        const payloadText = text.slice(type.length).trim();
        const payload = payloadText ? JSON.parse(payloadText) : {};
        startEncoder(payload);
        break;
      }
      case "encoder-stop":
        stopEncoder();
        break;
      case "close":
        closeChannel();
        break;
      case "exit":
        process.exit(0);
      default:
        break;
    }
  } catch (error) {
    logger.error(error);
    process.stderr.write(String(error));
  }
});

process.on("exit", () => {
  stopEncoder();
  closeChannel();
  if (rpio && typeof rpio.terminate === "function") {
    try {
      rpio.terminate();
      logger.info("pigpio terminated");
    } catch (e) {}
  }
  logger.error("gpio server exit");
});

process.on("disconnect", () => {
  logger.error("gpio server disconnect");
  process.exit(0);
});
