import { RowDataPacket } from 'mysql2';
import { pool } from '../config/db.js';
import { MENUS } from '../constants/menus.js';

interface PermissionRow extends RowDataPacket {
  menu_key: string;
  can_create: number;
  can_read: number;
  can_update: number;
  can_delete: number;
  can_approve: number;
  can_revise_ace: number;
  can_enter_actuals: number;
}

export interface PermissionDto {
  menuKey: string;
  menuLabel: string;
  canCreate: boolean;
  canRead: boolean;
  canUpdate: boolean;
  canDelete: boolean;
  canApprove: boolean;
  canReviseAce: boolean;
  canEnterActuals: boolean;
  common: boolean;
}

// Dashboard is a landing page every role can see — it isn't customized per role,
// so it's never read from or written to role_permissions; it's always this fixed value.
export const COMMON_MENU_KEY = 'dashboard';
const COMMON_MENU_PERMISSION = {
  canCreate: false,
  canRead: true,
  canUpdate: false,
  canDelete: false,
  canApprove: false,
  canReviseAce: false,
  canEnterActuals: false,
};

export async function getRolePermissions(roleId: number): Promise<PermissionDto[]> {
  const [rows] = await pool.query<PermissionRow[]>(
    `SELECT menu_key, can_create, can_read, can_update, can_delete, can_approve, can_revise_ace, can_enter_actuals
     FROM role_permissions WHERE role_id = ?`,
    [roleId],
  );
  const byKey = new Map(rows.map((r) => [r.menu_key, r]));

  return MENUS.map((menu) => {
    if (menu.key === COMMON_MENU_KEY) {
      return { menuKey: menu.key, menuLabel: menu.label, ...COMMON_MENU_PERMISSION, common: true };
    }
    const row = byKey.get(menu.key);
    return {
      menuKey: menu.key,
      menuLabel: menu.label,
      canCreate: !!row?.can_create,
      canRead: !!row?.can_read,
      canUpdate: !!row?.can_update,
      canDelete: !!row?.can_delete,
      canApprove: !!row?.can_approve,
      canReviseAce: !!row?.can_revise_ace,
      canEnterActuals: !!row?.can_enter_actuals,
      common: false,
    };
  });
}

/**
 * A user with no role assigned predates the roles system (the original seed
 * accounts) and isn't restricted by it — full access to every menu, so the
 * app doesn't lock itself out the moment roles/permissions ship.
 */
export function unrestrictedPermissions(): PermissionDto[] {
  return MENUS.map((menu) => ({
    menuKey: menu.key,
    menuLabel: menu.label,
    canCreate: true,
    canRead: true,
    canUpdate: true,
    canDelete: true,
    canApprove: true,
    canReviseAce: true,
    canEnterActuals: true,
    common: menu.key === COMMON_MENU_KEY,
  }));
}

/** Real per-action, server-side permission check — resolves the user's role (or the
 * unrestricted-legacy-account default) and looks up a single action on one menu. */
export async function hasPermission(
  userId: number,
  menuKey: string,
  action: 'canCreate' | 'canRead' | 'canUpdate' | 'canDelete' | 'canApprove' | 'canReviseAce' | 'canEnterActuals',
): Promise<boolean> {
  const [rows] = await pool.query<RowDataPacket[]>('SELECT role_id FROM users WHERE id = ?', [userId]);
  const roleId = rows[0]?.role_id as number | null | undefined;
  const perms = roleId ? await getRolePermissions(roleId) : unrestrictedPermissions();
  return !!perms.find((p) => p.menuKey === menuKey)?.[action];
}
