// FILE: backend/src/utils/rbac.js
// 03.2 2) เพิ่มตัวช่วย RBAC (ใหม่)
// Role-Based Access Control (RBAC) utilities
// - loadPrincipal(userId) to load user's roles, permissions, orgs, projects
// - canPerform(principal, permCode, {scope, orgId, projectId}) to check permission
// - Uses raw SQL queries via db/index.js
// - Permissions can be global, org-scoped, or project-scoped
// - Admin roles have special handling for org/project scope
// - SUPER_ADMIN bypasses all checks

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

/**
 * โหลด principal (บทบาท, องค์กร, โปรเจกต์) ให้ผู้ใช้
 */
export async function loadPrincipal(userId) {
  const [rolesRows] = await sql.query(
    /*sql*/ `
    SELECT ur.user_id, r.role_code, ur.org_id, ur.project_id
    FROM user_roles ur
    JOIN roles r ON r.role_id = ur.role_id
    WHERE ur.user_id = ?
  `,
    [userId]
  );

  const [permRows] = await sql.query(
    /*sql*/ `
    SELECT ur.user_id, r.role_code, p.permission_code, ur.org_id, ur.project_id
    FROM user_roles ur
    JOIN roles r ON r.role_id = ur.role_id
    JOIN role_permissions rp ON rp.role_id = r.role_id
    JOIN permissions p ON p.permission_id = rp.permission_id
    WHERE ur.user_id = ?
  `,
    [userId]
  );

  const roleCodes = new Set(rolesRows.map((r) => r.role_code));
  const isSuperAdmin = roleCodes.has("SUPER_ADMIN");

  // set องค์กรที่ผู้ใช้อยู่ (ใช้สำหรับ ADMIN scope)
  const orgIds = new Set(
    rolesRows.filter((r) => r.org_id).map((r) => r.org_id)
  );
  const projectIds = new Set(
    rolesRows.filter((r) => r.project_id).map((r) => r.project_id)
  );

  // map สิทธิเป็น: permCode -> { orgIds:Set, projectIds:Set }
  const perms = new Map();
  for (const r of permRows) {
    const key = r.permission_code;
    if (!perms.has(key))
      perms.set(key, { orgIds: new Set(), projectIds: new Set() });
    if (r.org_id) perms.get(key).orgIds.add(r.org_id);
    if (r.project_id) perms.get(key).projectIds.add(r.project_id);
  }

  return {
    userId,
    roleCodes, // Set<role_code>
    isSuperAdmin, // SUPER_ADMIN = true
    orgIds, // องค์กรของผู้ใช้ (จาก mapping)
    projectIds, // โปรเจกต์ของผู้ใช้ (จาก mapping)
    perms, // Map<permission_code, {orgIds:Set, projectIds:Set}>
  };
}

/**
 * ตรวจสิทธิ์ตามกติกา:
 * - SUPER_ADMIN: ผ่านทุกอย่าง (ข้าม org/project)
 * - ADMIN: ผ่านได้ "ภายใน org ของตัวเอง" เท่านั้น
 * - อื่น ๆ: ต้องถือ permission_code และเข้า scope ที่ถูกต้อง
 */
export function canPerform(
  principal,
  permCode,
  { scope = "global", orgId = null, projectId = null } = {}
) {
  if (!principal) return false;
  if (principal.isSuperAdmin) return true;
  const hasAdminRole = principal.roleCodes.has("ADMIN");

  if (scope === "global") return !!principal.perms.get(permCode);

  if (scope === "org") {
    if (!orgId) return false;
    if (hasAdminRole && principal.orgIds.has(orgId))
      return !!principal.perms.get(permCode);
    const entry = principal.perms.get(permCode);
    return !!entry && (entry.orgIds.has(orgId) || entry.orgIds.size === 0);
  }

  if (scope === "project") {
    if (!projectId) return false;
    if (hasAdminRole && principal.projectIds.has(projectId))
      return !!principal.perms.get(permCode);
    const entry = principal.perms.get(permCode);
    return (
      !!entry &&
      (entry.projectIds.has(projectId) || entry.projectIds.size === 0)
    );
  }

  return false;
}
