import { z } from 'zod';

export const RBAC_ROLES = ['edit', 'view', 'create', 'delete', 'run', 'expose'] as const;
export const RBAC_RESOURCES = ['*', 'servers', 'instances', 'secrets', 'projects', 'templates', 'users', 'groups', 'rbac', 'prompts', 'promptrequests'] as const;

/** Singular→plural map for resource names. */
const RESOURCE_ALIASES: Record<string, string> = {
  server: 'servers',
  instance: 'instances',
  secret: 'secrets',
  project: 'projects',
  template: 'templates',
  user: 'users',
  group: 'groups',
  prompt: 'prompts',
  promptrequest: 'promptrequests',
};

/** Normalize a resource name to its canonical plural form. */
export function normalizeResource(resource: string): string {
  return RESOURCE_ALIASES[resource] ?? resource;
}

export const RbacSubjectSchema = z.object({
  kind: z.enum(['User', 'Group', 'ServiceAccount']),
  name: z.string().min(1),
});

/** Resource binding: role grants access to a resource type (optionally scoped to a named instance). */
export const ResourceBindingSchema = z.object({
  role: z.enum(RBAC_ROLES),
  resource: z.string().min(1).transform(normalizeResource),
  name: z.string().min(1).optional(),
});

/** Operation binding: 'run' role grants access to a named operation. */
export const OperationBindingSchema = z.object({
  role: z.literal('run'),
  action: z.string().min(1),
});

/** Union of both binding types. */
export const RbacRoleBindingSchema = z.union([
  ResourceBindingSchema,
  OperationBindingSchema,
]);

export type RbacSubject = z.infer<typeof RbacSubjectSchema>;
export type ResourceBinding = z.infer<typeof ResourceBindingSchema>;
export type OperationBinding = z.infer<typeof OperationBindingSchema>;
export type RbacRoleBinding = z.infer<typeof RbacRoleBindingSchema>;

export function isResourceBinding(b: RbacRoleBinding): b is ResourceBinding {
  return 'resource' in b;
}

export function isOperationBinding(b: RbacRoleBinding): b is OperationBinding {
  return 'action' in b;
}

export const CreateRbacDefinitionSchema = z.object({
  name: z.string().min(1).max(100).regex(/^[a-z0-9-]+$/, 'Name must be lowercase alphanumeric with hyphens'),
  subjects: z.array(RbacSubjectSchema).min(1),
  roleBindings: z.array(RbacRoleBindingSchema).min(1),
});

export const UpdateRbacDefinitionSchema = z.object({
  subjects: z.array(RbacSubjectSchema).min(1).optional(),
  roleBindings: z.array(RbacRoleBindingSchema).min(1).optional(),
});

export type CreateRbacDefinitionInput = z.infer<typeof CreateRbacDefinitionSchema>;
export type UpdateRbacDefinitionInput = z.infer<typeof UpdateRbacDefinitionSchema>;
