// FILE: src/middleware/requirePerm.js
// 03.2 4) เพิ่ม middleware requirePerm (ใหม่)
// นำ middleware นี้ไปใส่ หลัง loadPrincipal เสมอ เช่น app.use('/api', authJwt(), loadPrincipalMw(), requirePerm('correspondence.create', {scope:'org', getOrgId: req=>...}), routes)
// หรือใส่ใน route เดี่ยวๆ ก็ได้ เช่น router.post('/', requirePerm('correspondence.create', {scope:'org', getOrgId: req=>...}), (req,res)=>{...})
// Permission requirement middleware with scope support
// - Uses canPerform() utility from rbac.js
// - Supports global, org, and project scopes
// - Requires req.principal to be populated (e.g. via loadPrincipal middleware)
// เช็คตาม perm_code + ABAC อัตโนมัติจาก permissions.scope_level
import sql from "../db/index.js";

let _permMap = null;
let _loadedAt = 0;
const TTL_MS = 60_000;

async function getPermRegistry() {
  const now = Date.now();
  if (_permMap && now - _loadedAt < TTL_MS) return _permMap;
  const [rows] = await sql.query(
    `SELECT perm_code, scope_level FROM permissions WHERE is_active=1`
  );
  _permMap = new Map(rows.map(r => [r.perm_code, r.scope_level])); // GLOBAL | ORG | PROJECT
  _loadedAt = now;
  return _permMap;
}

/**
 * requirePerm('rfas.view', { projectParam: 'project_id', orgParam: 'org_id' })
 * - GLOBAL: แค่มี perm ก็ผ่าน
 * - ORG:    ต้องมี perm + อยู่ใน org scope (อ่าน org_id จาก param หากระบุ; ไม่ระบุจะใช้ req.principal.org_id)
 * - PROJECT:ต้องมี perm + อยู่ใน project scope (อ่าน project_id จาก param)
 */
export function requirePerm(permCode, { projectParam, orgParam } = {}) {
  return async (req, res, next) => {
    const p = req.principal;
    if (!p) return res.status(401).json({ error: "Unauthenticated" });

    if (!(p.is_superadmin || p.permissions?.has?.(permCode))) {
      return res.status(403).json({ error: "FORBIDDEN", need: permCode });
    }

    const registry = await getPermRegistry();
    const scope = registry.get(permCode) || "GLOBAL";

    const readParam = (name) => req.params?.[name] ?? req.query?.[name] ?? req.body?.[name];

    if (scope === "PROJECT") {
      const pid = Number(projectParam ? readParam(projectParam) : undefined);
      if (!p.is_superadmin) {
        if (!pid || !p.inProject(pid)) {
          return res.status(403).json({ error: "FORBIDDEN_PROJECT", project_id: pid || null });
        }
      }
    } else if (scope === "ORG") {
      const oid = Number(orgParam ? readParam(orgParam) : p.org_id);
      if (!p.is_superadmin) {
        if (!oid || !p.inOrg(oid)) {
          return res.status(403).json({ error: "FORBIDDEN_ORG", org_id: oid || null });
        }
      }
    }
    next();
  };
}