/**
 * cli:scaffold-controller — types.ts
 */
import { z } from 'zod'

export const ControllerFieldSchema = z.object({
  name: z.string().min(1),
  type: z.string().min(1),
  required: z.boolean().default(true),
})

/**
 * Per-page mode (Step 3 of the per-page vertical-slice refactor): every
 * non-CRUD action declared in the BA's `BaScreen.Config.actions[]` becomes
 * one custom controller endpoint. Codes outside the standard REST set
 * (create/update/delete) are passed here and emitted as
 * `[HttpPost("{id:guid}/{code}")]` (row scope), `[HttpPost("bulk/{code}")]`
 * (bulk scope), or `[HttpPost("{code}")]` (header scope).
 *
 * The legacy `actions[]` enum stays untouched for permission constants and
 * for backwards compat with batch-entity callers; `customActions` is the
 * additive per-page input.
 */
export const ControllerCustomActionSchema = z.object({
  /** Action code (kebab/lowercase) — single source of truth across the whole
   *  vertical slice (URL segment, service method, hook). Examples: `archive`,
   *  `duplicate`, `approve`, `sync-from-proconcept`.
   *  Per-page mode: ba-develop derives this directly from
   *  `pageSpec.actions[].endpoint` (the verbatim URL segment) so frontend and
   *  backend cannot drift. @see lib/page-spec-actions.ts. */
  code: z.string().min(1).regex(/^[a-z][a-z0-9-]*$/, 'code must be kebab-case'),
  scope: z.enum(['row', 'bulk', 'header']).default('row'),
  /** HTTP verb. Defaults POST (state mutations). Set GET for read-only
   *  compute endpoints (`analyze-impact`, `validate`, …) — the generator omits
   *  `[FromBody]` automatically. */
  httpMethod: z.enum(['GET', 'POST', 'PUT', 'PATCH', 'DELETE']).default('POST'),
  /** C# DTO type name expected in the request body, or null when there's no
   *  body. Set by build-page-context.ts when the linked BR has parameters.
   *  Ignored when `httpMethod === 'GET'` (no body on GETs). */
  payloadDto: z.string().nullable().optional(),
  /** C# response type name. `NoContent` for 204 endpoints (state mutations
   *  like archive that return nothing). */
  responseDto: z.string().min(1).default('NoContent'),
  /** Permission action segment ({app}.{module}.{section}.{permissionAction})
   *  — defaults to `update` because most state-transition actions
   *  (archive/restore/activate/deactivate) reuse the existing Update perm. */
  permissionAction: z.string().min(1).default('update'),
})

export const ScaffoldControllerInputSchema = z.object({
  name: z.string().min(1).regex(/^[A-Z][A-Za-z0-9]*$/),
  pluralName: z.string().optional(),
  module: z.string().min(1),
  section: z.string().min(1),
  appCode: z.string().min(1),
  namespace: z.string().optional(),
  navRoute: z
    .string()
    .regex(/^[\w]+(\.[\w]+)+$/, 'NavRoute must be dot-separated hierarchy: module.section[.resource...]')
    .refine(v => !v.endsWith('.') && !v.startsWith('.'), 'NavRoute cannot start or end with a dot'),
  permissionPrefix: z.string().optional(),
  actions: z.array(z.enum(['read', 'create', 'update', 'delete', 'export', 'import', 'approve', 'reject', 'assign', 'execute'])).default(['read', 'create', 'update', 'delete']),
  customActions: z.array(ControllerCustomActionSchema).default([]),
  fields: z.array(ControllerFieldSchema).default([]),
  projectPath: z.string().min(1),
})

export type ControllerField = z.infer<typeof ControllerFieldSchema>
export type ControllerCustomAction = z.infer<typeof ControllerCustomActionSchema>
export type ScaffoldControllerInput = z.infer<typeof ScaffoldControllerInputSchema>
export interface GeneratedFile { path: string; content: string }
export interface ValidationResult { valid: boolean; errors: string[]; warnings: string[] }
