/**
 * Sarfees driver bind + hunting proofs for ARSC 2× hours.
 * Reads the live bot sqlite on this VPS via python3 (sqlite3 CLI may be absent).
 * HMAC uses the snapshot secret so every node can verify.
 */
const { execFile } = require("child_process");
const { promisify } = require("util");
const crypto = require("crypto");
const execFileAsync = promisify(execFile);

const DB = process.env.SARFEES_DB || "/opt/sarfees/sarfees.db";
const INTERNAL = process.env.SARFEES_INTERNAL_TOKEN || "sarmad-sarfees-bind-v156";
const SNAPSHOT_SECRET =
  process.env.SARMAD_SNAPSHOT_SECRET ||
  process.env.SARMAD_RESET_TOKEN ||
  "sarmad-dev-snapshot-secret";
const INTERVAL = 20 * 60;

function huntWindowId(networkTs) {
  return Math.floor(Number(networkTs || 0) / INTERVAL);
}

function huntHmacHex(address, window) {
  return crypto
    .createHmac("sha256", SNAPSHOT_SECRET)
    .update(`SARFEES-HUNT|${address}|${window}`)
    .digest("hex");
}

async function pySqlite(script, extraArgs = []) {
  try {
    const { stdout, stderr } = await execFileAsync(
      "python3",
      ["-c", script, DB, ...extraArgs],
      { timeout: 5000, maxBuffer: 2 * 1024 * 1024 }
    );
    return { ok: true, stdout: String(stdout || ""), stderr: String(stderr || "") };
  } catch (e) {
    return { ok: false, stdout: "", error: e && e.message ? e.message : String(e) };
  }
}

const ENSURE_SQL = `
import sqlite3, sys
db = sys.argv[1]
c = sqlite3.connect(db)
c.execute("CREATE TABLE IF NOT EXISTS sarmad_binds (telegram_id INTEGER PRIMARY KEY, srmd_address TEXT UNIQUE NOT NULL, bound_at TEXT)")
c.commit()
c.close()
`;

const LOOKUP_SQL = `
import sqlite3, json, sys
db, addr = sys.argv[1], sys.argv[2]
c = sqlite3.connect(db)
c.row_factory = sqlite3.Row
rows = c.execute(
    """SELECT b.srmd_address, COALESCE(us.driver_state,'idle') AS driver_state
       FROM sarmad_binds b
       LEFT JOIN user_states us ON us.user_id = b.telegram_id
       WHERE b.srmd_address = ? LIMIT 1""",
    (addr,),
).fetchall()
print(json.dumps([dict(r) for r in rows]))
c.close()
`;

const BIND_SQL = `
import sqlite3, sys
db, tid, addr = sys.argv[1], int(sys.argv[2]), sys.argv[3]
c = sqlite3.connect(db)
c.execute("CREATE TABLE IF NOT EXISTS sarmad_binds (telegram_id INTEGER PRIMARY KEY, srmd_address TEXT UNIQUE NOT NULL, bound_at TEXT)")
c.execute("DELETE FROM sarmad_binds WHERE telegram_id=? OR srmd_address=?", (tid, addr))
c.execute(
    "INSERT INTO sarmad_binds(telegram_id, srmd_address, bound_at) VALUES(?,?, datetime('now'))",
    (tid, addr),
)
c.commit()
c.close()
print("ok")
`;

async function ensureBindTable() {
  await pySqlite(ENSURE_SQL);
}

async function lookupHunting(address) {
  await ensureBindTable();
  const r = await pySqlite(LOOKUP_SQL, [String(address || "")]);
  if (!r.ok) return { bound: false, hunting: false, dbMissing: true };
  let rows = [];
  try {
    rows = JSON.parse(String(r.stdout || "").trim() || "[]");
  } catch (_) {
    return { bound: false, hunting: false, dbMissing: true };
  }
  if (!rows.length) return { bound: false, hunting: false };
  const state = String(rows[0].driver_state || "idle");
  return { bound: true, hunting: state === "searching", driverState: state };
}

async function bindAddress(telegramId, address) {
  const id = Number(telegramId);
  const addr = String(address || "");
  if (!id || !addr) return { ok: false, error: "bad bind" };
  const r = await pySqlite(BIND_SQL, [String(id), addr]);
  if (!r.ok) return { ok: false, error: r.error || "sqlite failed" };
  return { ok: true, telegramId: id, address: addr };
}

function checkInternalToken(req) {
  const got = String(req.headers["x-sarfees-token"] || "");
  return got === INTERNAL;
}

module.exports = {
  huntWindowId,
  huntHmacHex,
  lookupHunting,
  bindAddress,
  checkInternalToken,
  INTERVAL,
};
