import { z } from 'zod';

import { PERMISSION_CATALOG } from '@/lib/auth/permissions';

/**
 * Role-permission validation schema, built from the canonical
 * `PERMISSION_CATALOG` (`src/lib/auth/permissions.ts`) so it can never drift
 * from the per-user override allow-list again (audit finding L23).
 *
 * Previously this was `z.record(z.string(), z.boolean())` per resource, which
 * accepted ARBITRARY action keys and was missing several resources entirely
 * (`yachts`, `companies`, `memberships`, `tenancies`, `payments`,
 * `residential_*`, `document_templates`). It now:
 *   - rejects unknown resources (top-level `.strict()`),
 *   - rejects unknown actions within a resource (per-resource `.strict()`),
 *   - accepts full OR partial action maps (each action `.optional()`), so the
 *     seed defaults and the admin role form (which send full maps) and any
 *     future partial-patch caller all validate.
 */
const rolePermissionsSchema = z
  .object(
    Object.fromEntries(
      Object.entries(PERMISSION_CATALOG).map(([resource, actions]) => [
        resource,
        z
          .object(Object.fromEntries(actions.map((action) => [action, z.boolean().optional()])))
          .strict(),
      ]),
    ),
  )
  .strict();

export const createRoleSchema = z.object({
  name: z.string().min(1).max(100),
  description: z.string().max(500).optional(),
  permissions: rolePermissionsSchema,
});

export type CreateRoleInput = z.infer<typeof createRoleSchema>;

export const updateRoleSchema = z.object({
  name: z.string().min(1).max(100).optional(),
  description: z.string().max(500).nullable().optional(),
  permissions: rolePermissionsSchema.optional(),
});

export type UpdateRoleInput = z.infer<typeof updateRoleSchema>;
