import fs from 'fs';
import path from 'path';
import { SerialPort } from 'serialport';

interface Config {
  hostPort: string;
  devicePort: string;
  baudRate: number;
  logFile: string;
  dataBits: 8 | 5 | 6 | 7 | undefined;
  stopBits: 1 | 2 | 1.5 | undefined;
  parity: 'none' | 'even' | 'odd' | 'mark' | 'space';
  protocol: 'custom' | 'modbus';
  enableCRC?: boolean;
}

function loadConfig(): Config {
  const configPath = path.resolve(__dirname, '../config.json');
  if (!fs.existsSync(configPath)) {
    console.error('❌ 配置文件 config.json 未找到');
    process.exit(1);
  }

  const configText = fs.readFileSync(configPath, 'utf-8');
  try {
    const raw = JSON.parse(configText);

    const config: Config = {
      hostPort: raw.hostPort,
      devicePort: raw.devicePort,
      baudRate: raw.baudRate,
      logFile: raw.logFile || path.resolve(process.cwd(), 'serial.log'),
      dataBits: raw.dataBits || 8,
      stopBits: raw.stopBits || 1,
      parity: raw.parity || 'none',
      protocol: raw.protocol === 'modbus' ? 'modbus' : 'custom',
      enableCRC: raw.enableCRC === true
    };

    return config;
  } catch (err) {
    console.error('❌ 配置文件格式错误:', err);
    process.exit(1);
  }
}

function formatTime(date: Date): string {
  const pad = (n: number) => n.toString().padStart(2, '0');
  return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} `
       + `${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
}

function formatLogLine(direction: string, data: Buffer, protocol: 'custom' | 'modbus'): string {
  const timestamp = formatTime(new Date());
  const hex = data.toString('hex').toUpperCase().replace(/(.{2})/g, '$1 ').trim();

  if (protocol === 'modbus') {
    return `${timestamp} ${direction} HEX: ${hex}`;
  } else {
    const ascii = data.toString().replace(/[^\x20-\x7E]/g, '.');
    return `${timestamp} ${direction} HEX: ${hex} ASCII: ${ascii}`;
  }
}

function logAndPrint(stream: fs.WriteStream, direction: string, data: Buffer, protocol: 'custom' | 'modbus') {
  const line = formatLogLine(direction, data, protocol);
  stream.write(line + '\n');
  console.log(line);
}

function calculateCRC16(buffer: Buffer): Buffer {
  let crc = 0xFFFF;

  for (let i = 0; i < buffer.length; i++) {
    crc ^= buffer[i];
    for (let j = 0; j < 8; j++) {
      if ((crc & 0x0001) !== 0) {
        crc >>= 1;
        crc ^= 0xA001;
      } else {
        crc >>= 1;
      }
    }
  }

  const lo = crc & 0xFF;
  const hi = (crc >> 8) & 0xFF;
  return Buffer.from([lo, hi]);
}

function startProxy(config: Config) {
  const { hostPort, devicePort, baudRate, dataBits, stopBits, parity, logFile, protocol, enableCRC } = config;

  const logStream = fs.createWriteStream(logFile, { flags: 'a' });

  const host = new SerialPort({ path: hostPort, baudRate, dataBits, stopBits, parity });
  const device = new SerialPort({ path: devicePort, baudRate, dataBits, stopBits, parity });

  host.on('data', data => {
    let outData = data;

    if (protocol === 'modbus' && enableCRC) {
      const crc = calculateCRC16(data);
      outData = Buffer.concat([data, crc]);
    }

    logAndPrint(logStream, '[主机 → 设备]', outData, protocol);
    device.write(outData);
  });

  device.on('data', data => {
    logAndPrint(logStream, '[设备 → 主机]', data, protocol);
    host.write(data);
  });

  host.on('error', err => console.error('主机端串口错误:', err.message));
  device.on('error', err => console.error('设备端串口错误:', err.message));

  console.log(`✅ 串口代理已启动：
  主机端：${hostPort}
  设备端：${devicePort}
  波特率：${baudRate}
  协议类型：${protocol}
  CRC 校验：${enableCRC ? '启用' : '关闭'}
  日志文件：${logFile}`);
}

startProxy(loadConfig());