const net = require("net");
const fs = require("fs");
const path = require("path");
const mysql = require("mysql2");

const config = require("./config.json");
// Prefer centralized Keyence config (../config/keyence.json) so UI and service stay in sync.
let sharedKeyenceCfg = null;
try {
  const sharedPath = path.join(__dirname, "..", "config", "keyence.json");
  if (fs.existsSync(sharedPath)) {
    sharedKeyenceCfg = JSON.parse(fs.readFileSync(sharedPath, "utf8"));
  }
} catch (e) { /* ignore */ }
if (sharedKeyenceCfg && typeof sharedKeyenceCfg === "object") {
  config.keyence = config.keyence || {};
  if (sharedKeyenceCfg.ip) config.keyence.ip = sharedKeyenceCfg.ip;
  if (sharedKeyenceCfg.port) config.keyence.port = sharedKeyenceCfg.port;
  if (typeof sharedKeyenceCfg.enabled !== "undefined") config.keyence.enabled = !!sharedKeyenceCfg.enabled;
}
const logFile = path.join(__dirname, "keyence_listener.log");

function logLine(msg) {
  const line = `[${new Date().toISOString()}] ${msg}\n`;
  fs.appendFile(logFile, line, () => {});
  console.log(line.trim());
}

const db = mysql.createPool({
  host: config.database.host,
  user: config.database.user,
  password: config.database.password,
  database: config.database.database,
  connectionLimit: 5
});

// Ensure tables exist
db.query(`CREATE TABLE IF NOT EXISTS keyence_status (
  id INT PRIMARY KEY,
  last_heartbeat DATETIME NULL,
  last_error TEXT NULL,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4`, () => {});

db.query(`CREATE TABLE IF NOT EXISTS keyence_logs (
  id INT AUTO_INCREMENT PRIMARY KEY,
  level ENUM('INFO','WARN','ERROR') DEFAULT 'INFO',
  message TEXT,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4`, () => {});

function logDb(level, message) {
  db.query(
    "INSERT INTO keyence_logs(level,message) VALUES(?,?)",
    [level, message],
    err => {
      if (err) {
        logLine("DB log error: " + err.message);
      }
    }
  );
}

function updateStatus(isOnline, errMsg) {
  const sql = `
    INSERT INTO keyence_status (id, last_heartbeat, last_error)
    VALUES (1, ?, ?)
    ON DUPLICATE KEY UPDATE last_heartbeat = VALUES(last_heartbeat), last_error = VALUES(last_error)
  `;
  const hb = isOnline ? new Date() : null;
  db.query(sql, [hb, errMsg || null], err => {
    if (err) logLine("Status update error: " + err.message);
  });
}

// Simple TCP client connecting to Keyence
function startClient() {
  logDb("INFO", "Connecting to Keyence...");
  logLine("Connecting to Keyence " + config.keyence.ip + ":" + config.keyence.port);

  const client = new net.Socket();
  let buffer = "";

  client.connect(config.keyence.port, config.keyence.ip, () => {
    logDb("INFO", "Connected to Keyence.");
    logLine("Connected to Keyence.");
    updateStatus(true, null);
  });

  client.on("data", chunk => {
    buffer += chunk.toString("utf8");
    let parts = buffer.split(/\r?\n/);
    buffer = parts.pop();
    for (const line of parts) {
      const trimmed = line.trim();
      if (!trimmed) continue;
      const msg = "BARCODE: " + trimmed;
      logDb("INFO", msg);
      updateStatus(true, null);
    }
  });

  client.on("error", err => {
    logDb("ERROR", "Keyence socket error: " + err.message);
    logLine("Socket error: " + err.message);
    updateStatus(false, err.message);
    setTimeout(startClient, 3000);
  });

  client.on("close", () => {
    logDb("WARN", "Keyence connection closed.");
    logLine("Keyence connection closed.");
    updateStatus(false, "Connection closed");
    setTimeout(startClient, 3000);
  });
}

// Small HTTP health endpoint (optional)
const http = require("http");
const httpServer = http.createServer((req, res) => {
  if (req.url === "/health") {
    db.query("SELECT last_heartbeat,last_error FROM keyence_status WHERE id=1", (err, rows) => {
      const body = {
        ok: !err,
        status: rows && rows[0] ? {
          last_heartbeat: rows[0].last_heartbeat,
          last_error: rows[0].last_error
        } : null
      };
      res.writeHead(err ? 500 : 200, { "Content-Type": "application/json" });
      res.end(JSON.stringify(body));
    });
  } else {
    res.writeHead(200, { "Content-Type": "text/plain" });
    res.end("Keyence listener running");
  }
});

httpServer.listen(config.http.port, () => {
  logLine("HTTP health server on port " + config.http.port);
});

// global error safety
process.on("uncaughtException", err => {
  logLine("Uncaught exception: " + err.message);
  logDb("ERROR", "Uncaught exception: " + err.message);
});

process.on("unhandledRejection", err => {
  logLine("Unhandled rejection: " + (err && err.message ? err.message : String(err)));
  logDb("ERROR", "Unhandled rejection: " + String(err));
});

startClient();
