/**
 * scaffold-screen-controller — types.ts
 *
 * Zod schemas for the screen-driven controller scaffolder. The PageSpec sub-schema
 * mirrors the contract authored by `/ba-create-prd` in `pagespecs/<Entity>.<view>.md`
 * (only the fields backend cares about — i18nKeys, formatHint, etc. are ignored).
 */

import { z } from 'zod'

/** A column referenced by a list-view pagespec. Backend cares about key + isComputed. */
export const PageSpecColumnSchema = z.object({
  key: z.string().min(1),
  labelKey: z.string().optional(),
  formatHint: z.string().optional(),
  sortable: z.boolean().optional(),
  filterable: z.boolean().optional(),
  searchable: z.boolean().optional(),
  isComputed: z.boolean().optional(),
}).passthrough()

export type PageSpecColumn = z.infer<typeof PageSpecColumnSchema>

/** A custom action on the screen (header / row / bulk). Mirrors PageCustomActionSchema. */
export const PageSpecActionSchema = z.object({
  code: z.string().min(1),
  kind: z.enum(['api', 'navigate']).optional().default('api'),
  scope: z.enum(['header', 'row', 'bulk']).optional().default('header'),
  endpoint: z.string().optional(),
  httpMethod: z.enum(['GET', 'POST', 'PUT', 'PATCH', 'DELETE']).optional().default('POST'),
  payloadDto: z.string().nullable().optional(),
  responseDto: z.string().nullable().optional(),
  permission: z.string().optional(),
  variant: z.string().optional(),
  labelKey: z.string().optional(),
  ucReference: z.string().optional(),
  targetScreen: z.string().optional(),
  targetRoute: z.string().optional(),
}).passthrough()

export type PageSpecAction = z.infer<typeof PageSpecActionSchema>

/** The pagespec machine block (fenced JSON in pagespecs/<Entity>.<view>.md). */
export const PageSpecSchema = z.object({
  screenCode: z.string().regex(/^SCR-[A-Z0-9_-]+$/),
  appCode: z.string().min(1),
  module: z.string().min(1),
  section: z.string().min(1),
  entity: z.string().min(1),
  view: z.enum(['list', 'detail', 'form', 'dashboard', 'kanban', 'card', 'app-home', 'module-home', 'section-home']),
  permission: z.string().regex(/^[a-z0-9-]+\.[a-z0-9-]+\.[a-z0-9-]+$/),
  linkedUseCases: z.array(z.string()).optional().default([]),
  linkedBusinessRules: z.array(z.string()).optional().default([]),
  screenType: z.string().optional(),
  columns: z.array(PageSpecColumnSchema).optional().default([]),
  actions: z.array(PageSpecActionSchema).optional().default([]),
}).passthrough()

export type PageSpec = z.infer<typeof PageSpecSchema>

/** CLI input. The scaffolder reads moduleDir/pagespecs/*.md, keeps the
 *  pagespecs matching (section, entity), and emits exactly one
 *  {EntityPlural}ScreenController.cs + one {Entity}{View}ScreenDto per
 *  read screen (list / detail). The caller (Phase 2b orchestrator in
 *  /ba-develop) fans out per (section, entity) — one agent per controller. */
export const ScaffoldScreenControllerSpecSchema = z.object({
  /** Lowercase section code (matches pagespec.section). */
  section: z.string().min(1),
  /** PascalCase singular entity name (matches pagespec.entity). The URL
   *  segment is the lowercase plural derived from this via pluralize(). */
  entity: z.string().min(1),
  /** Lowercase module code (matches pagespec.module). */
  module: z.string().min(1),
  /** Lowercase app code (matches pagespec.appCode). */
  appCode: z.string().min(1),
  /** PascalCase namespace root (e.g. "Crm" for Crm.Api / Crm.Application). */
  namespace: z.string().min(1),
  /** Directory containing the pagespecs/ subfolder. */
  moduleDir: z.string().min(1),
  /** Project root where files are written. */
  projectPath: z.string().min(1),
})

export type ScaffoldScreenControllerSpec = z.infer<typeof ScaffoldScreenControllerSpecSchema>

export const GeneratedFileSchema = z.object({
  path: z.string(),
  content: z.string(),
})

export type GeneratedFile = z.infer<typeof GeneratedFileSchema>

export const ResultSchema = z.object({
  success: z.boolean(),
  error: z.string().optional(),
  filesGenerated: z.number(),
  files: z.array(GeneratedFileSchema),
  todos: z.array(z.string()).default([]),
})

export type Result = z.infer<typeof ResultSchema>
