/**
 * @file HTTP surface for cross-lane named locks (`server/lib/named-lock.js`).
 * Every route is single-shot — this layer never blocks waiting for a lock to
 * free up. The CLI (`ccam lock acquire`) owns the polling loop; CCAM's
 * server-side primitives stay non-orchestrating, same as every other lane
 * route in this project.
 * @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
 */

const { Router } = require("express");
const namedLock = require("../lib/named-lock");
const { sameOriginGuard } = require("./run");

const router = Router();

router.get("/", (_req, res) => {
  res.json({ locks: namedLock.listLocks() });
});

router.post("/:name/acquire", sameOriginGuard, (req, res) => {
  const holder = typeof req.body?.holder === "string" ? req.body.holder.trim() : "";
  if (!holder) {
    return res.status(400).json({ error: { code: "EBADHOLDER", message: "holder is required" } });
  }
  const result = namedLock.tryAcquire(req.params.name, holder);
  if (result.acquired) return res.json(result);
  res.status(409).json(result);
});

router.post("/:name/release", sameOriginGuard, (req, res) => {
  const holder = typeof req.body?.holder === "string" ? req.body.holder.trim() : "";
  if (!holder) {
    return res.status(400).json({ error: { code: "EBADHOLDER", message: "holder is required" } });
  }
  try {
    namedLock.release(req.params.name, holder);
    res.json({ ok: true });
  } catch (err) {
    if (err.code === "ENOLOCK") {
      return res.status(404).json({ error: { code: err.code, message: err.message } });
    }
    if (err.code === "ENOTHOLDER") {
      return res.status(409).json({
        error: { code: err.code, message: err.message, currentHolder: err.currentHolder },
      });
    }
    res.status(500).json({ error: { code: err.code, message: err.message } });
  }
});

module.exports = router;
