// FILE: src/middleware/loadPrincipal.js
// 03.2 4) เพิ่ม middleware loadPrincipal (ใหม่)
// นำ middleware นี้ไปใส่ หลัง verify JWT เสมอ เช่น app.use('/api', authJwt(), loadPrincipalMw(), routes)
// Load principal (roles + permissions) middleware
// - Uses rbac.js utility to load principal info
// - Attaches to req.principal
// - Requires req.user.user_id to be populated (e.g. via auth.js or authJwt.js)
// โหลด principal จาก DB แล้วแนบไว้ใน req.principal
// NOTE: ตรงนี้สมมุติว่าคุณมี service/query ฝั่ง DB อยู่แล้ว (เช่น sql/Sequelize)
//       ถ้าคุณมีฟังก์ชันโหลด principal อยู่ที่อื่น ให้แทน logic DB ตรง FIXME ด้านล่าง
// ใช้ req.auth.user_id และตั้ง req.principal ให้ครบ (RBAC + ABAC)

import sql from "../db/index.js";

export function loadPrincipalMw() {
  return async (req, res, next) => {
    try {
      const uid = req?.auth?.user_id || req?.user?.user_id;
      if (!uid) return res.status(401).json({ error: "Unauthenticated" });

      // --- 1) users (รวม org_id)
      const [[u]] = await sql.query(
        `SELECT user_id, username, email, first_name, last_name, org_id, is_active
           FROM users WHERE user_id=? LIMIT 1`,
        [uid]
      );
      if (!u || u.is_active === 0) return res.status(401).json({ error: "Unauthenticated" });

      // --- 2) roles (global)
      const [roleRows] = await sql.query(
        `SELECT r.role_id, r.role_code, r.role_name
           FROM user_roles ur
           JOIN roles r ON r.role_id = ur.role_id
          WHERE ur.user_id=?`,
        [uid]
      );
      const roleCodes = new Set(roleRows.map(r => r.role_code));
      const is_superadmin = roleCodes.has("SUPER_ADMIN");

      // --- 3) permissions (ผ่าน role_permissions)
      const [permRows] = await sql.query(
        `SELECT DISTINCT p.perm_code
           FROM user_roles ur
           JOIN role_permissions rp ON rp.role_id = ur.role_id
           JOIN permissions p       ON p.permission_id = rp.permission_id AND p.is_active=1
          WHERE ur.user_id=?`,
        [uid]
      );
      const permSet = new Set(permRows.map(x => x.perm_code));

      // --- 4) project scope (user_project_roles)
      const [projRows] = await sql.query(
        `SELECT DISTINCT project_id FROM user_project_roles WHERE user_id=?`,
        [uid]
      );
      const project_ids = projRows.map(r => r.project_id);

      // --- 5) org scope: users.org_id + orgs จาก project_parties ของโปรเจ็คที่เข้าถึง
      const baseOrgIds = u.org_id ? [u.org_id] : [];
      let projOrgIds = [];
      if (project_ids.length) {
        const [rows] = await sql.query(
          `SELECT DISTINCT org_id FROM project_parties WHERE project_id IN (?)`,
          [project_ids]
        );
        projOrgIds = rows.map(r => r.org_id);
      }
      const org_ids = Array.from(new Set([...baseOrgIds, ...projOrgIds]));

      req.principal = {
        user_id: u.user_id,
        username: u.username,
        email: u.email,
        first_name: u.first_name,
        last_name: u.last_name,
        org_id: u.org_id || null,

        roles: roleRows.map(r => ({ role_id: r.role_id, role_code: r.role_code, role_name: r.role_name })),
        permissions: permSet,          // Set ของ perm_code
        project_ids,
        org_ids,
        is_superadmin,

        // helpers
        can: (code) => is_superadmin || permSet.has(code),
        canAny: (codes=[]) => is_superadmin || codes.some(c => permSet.has(c)),
        canAll: (codes=[]) => is_superadmin || codes.every(c => permSet.has(c)),
        inProject: (pid) => is_superadmin || project_ids.includes(Number(pid)),
        inOrg: (oid) => is_superadmin || org_ids.includes(Number(oid)),
      };

      next();
    } catch (err) {
      console.error("loadPrincipal error", err);
      res.status(500).json({ error: "Failed to load principal" });
    }
  };
}
