"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateImportReviewReviewStage = generateImportReviewReviewStage;
function generateImportReviewReviewStage() {
    return `
function ReviewStage({
  preview,
  isLoading,
  onExecute,
  onReset,
}: Readonly<{
  preview: ImportPreviewResponse
  isLoading: boolean
  onExecute: (options: {
    ignoreErrors: boolean
    confirmDeletes: boolean
    selectedDeltaIndicesByModel: SelectedDeltaIndicesByModel
  }) => Promise<void>
  onReset: () => void
}>) {
  const [activeModel, setActiveModel] = useState<string | null>(null)
  const [ignoreErrors, setIgnoreErrors] = useState(false)
  const [confirmDeletesChecked, setConfirmDeletesChecked] = useState(false)
  const [cancelDialogOpen, setCancelDialogOpen] = useState(false)
  const [executeDialogOpen, setExecuteDialogOpen] = useState(false)
  const [selectedDeltaIndicesByModel, setSelectedDeltaIndicesByModel] = useState<SelectedDeltaIndicesByModel>(() =>
    buildDefaultSelection(preview.models),
  )

  useEffect(() => {
    setSelectedDeltaIndicesByModel(buildDefaultSelection(preview.models))
    setActiveModel(null)
    setIgnoreErrors(false)
    setConfirmDeletesChecked(false)
    setCancelDialogOpen(false)
    setExecuteDialogOpen(false)
  }, [preview])

  const modelEntries = useMemo(
    () => Object.entries(preview.models).filter(([, model]) => model.items.length > 0),
    [preview.models],
  )

  const selectedStatsByModel = useMemo(() => {
    const result: Record<string, { selected: number; executable: number; selectedDeletes: number }> = {}
    for (const [modelName, model] of modelEntries) {
      const selectedSet = new Set(selectedDeltaIndicesByModel[modelName] ?? [])
      let selected = 0
      let executable = 0
      let selectedDeletes = 0

      for (const item of model.items) {
        if (!isExecutableItem(item) || typeof item.deltaIndex !== 'number') {
          continue
        }

        executable++
        if (selectedSet.has(item.deltaIndex)) {
          selected++
          if (item.type === 'delete') {
            selectedDeletes++
          }
        }
      }

      result[modelName] = { selected, executable, selectedDeletes }
    }
    return result
  }, [modelEntries, selectedDeltaIndicesByModel])

  const totalSelected = Object.values(selectedStatsByModel).reduce((acc, item) => acc + item.selected, 0)
  const totalExecutable = Object.values(selectedStatsByModel).reduce((acc, item) => acc + item.executable, 0)
  const selectedDeletes = Object.values(selectedStatsByModel).reduce((acc, item) => acc + item.selectedDeletes, 0)

  const hasProcessingErrors = !!preview.processingErrors?.length
  const errorCount = preview.summary.errors
  const hasRowErrors = errorCount > 0
  const canExecute =
    !hasProcessingErrors &&
    totalSelected > 0 &&
    (selectedDeletes === 0 || confirmDeletesChecked) &&
    (!hasRowErrors || ignoreErrors)

  const hasSelectionChanges = !selectionEquals(selectedDeltaIndicesByModel, buildDefaultSelection(preview.models))

  const handleExecuteConfirmed = () => {
    setExecuteDialogOpen(false)
    void onExecute({
      ignoreErrors,
      confirmDeletes: selectedDeletes === 0 || confirmDeletesChecked,
      selectedDeltaIndicesByModel,
    })
  }

  return (
    <>
      <AlertDialog open={cancelDialogOpen} onOpenChange={setCancelDialogOpen}>
        <AlertDialogContent>
          <AlertDialogHeader>
            <AlertDialogTitle>Discard Preview?</AlertDialogTitle>
            <AlertDialogDescription>
              {hasSelectionChanges
                ? 'This will discard the uploaded preview and your row selections.'
                : 'This will discard the uploaded preview.'}
            </AlertDialogDescription>
          </AlertDialogHeader>
          <AlertDialogFooter>
            <AlertDialogCancel>Continue Reviewing</AlertDialogCancel>
            <AlertDialogAction onClick={onReset}>Discard and Return</AlertDialogAction>
          </AlertDialogFooter>
        </AlertDialogContent>
      </AlertDialog>

      <AlertDialog open={executeDialogOpen} onOpenChange={setExecuteDialogOpen}>
        <AlertDialogContent>
          <AlertDialogHeader>
            <AlertDialogTitle>Execute Selected Changes?</AlertDialogTitle>
            <AlertDialogDescription>
              You are about to execute {totalSelected} selected changes ({selectedDeletes} delete{selectedDeletes === 1 ? '' : 's'}).
            </AlertDialogDescription>
          </AlertDialogHeader>
          <AlertDialogFooter>
            <AlertDialogCancel>Back</AlertDialogCancel>
            <AlertDialogAction onClick={handleExecuteConfirmed}>Execute</AlertDialogAction>
          </AlertDialogFooter>
        </AlertDialogContent>
      </AlertDialog>

      <div className="grid gap-4 lg:grid-cols-[360px_1fr]">
        <PreviewSidebar
          filename={preview.filename}
          modelEntries={modelEntries}
          selectedStatsByModel={selectedStatsByModel}
          setSelectedDeltaIndicesByModel={setSelectedDeltaIndicesByModel}
          activeModel={activeModel}
          onSelectModel={setActiveModel}
          onCancel={() => setCancelDialogOpen(true)}
          onExecute={() => setExecuteDialogOpen(true)}
          canExecute={canExecute}
          isLoading={isLoading}
          totalSelected={totalSelected}
          totalExecutable={totalExecutable}
          selectedDeletes={selectedDeletes}
          confirmDeletesChecked={confirmDeletesChecked}
          setConfirmDeletesChecked={setConfirmDeletesChecked}
          errorCount={errorCount}
          ignoreErrors={ignoreErrors}
          setIgnoreErrors={setIgnoreErrors}
        />

        <div className="flex min-w-0 flex-col gap-4">
          {hasProcessingErrors && (
            <Card className="border-destructive">
              <CardHeader>
                <CardTitle className="text-destructive">Processing Errors</CardTitle>
              </CardHeader>
              <CardContent className="space-y-2">
                {preview.processingErrors?.map((err) => (
                  <Alert key={err} variant="destructive">
                    <AlertDescription>
                      <pre className="whitespace-pre-wrap break-all text-sm">{err}</pre>
                    </AlertDescription>
                  </Alert>
                ))}
              </CardContent>
            </Card>
          )}

          {!activeModel && (
            <OverviewTable
              modelEntries={modelEntries}
              selectedStatsByModel={selectedStatsByModel}
              onOpenModel={setActiveModel}
              onSelectAllModel={(modelName) =>
                setSelectedDeltaIndicesByModel((prev) => {
                  const model = preview.models[modelName]
                  return { ...prev, [modelName]: model ? selectModel(model) : [] }
                })
              }
              onDeselectAllModel={(modelName) =>
                setSelectedDeltaIndicesByModel((prev) => ({ ...prev, [modelName]: [] }))
              }
            />
          )}

          {activeModel && preview.models[activeModel] && (
            <ModelReviewPanel
              modelName={activeModel}
              model={preview.models[activeModel]}
              selectedIndices={selectedDeltaIndicesByModel[activeModel] ?? []}
              onSelectionChange={(indices) =>
                setSelectedDeltaIndicesByModel((prev) => ({ ...prev, [activeModel]: indices }))
              }
              onBack={() => setActiveModel(null)}
            />
          )}
        </div>
      </div>
    </>
  )
}

function PreviewSidebar({
  filename,
  modelEntries,
  selectedStatsByModel,
  setSelectedDeltaIndicesByModel,
  activeModel,
  onSelectModel,
  onCancel,
  onExecute,
  canExecute,
  isLoading,
  totalSelected,
  totalExecutable,
  selectedDeletes,
  confirmDeletesChecked,
  setConfirmDeletesChecked,
  errorCount,
  ignoreErrors,
  setIgnoreErrors,
}: Readonly<{
  filename: string
  modelEntries: [string, ImportPreviewModelSummary][]
  selectedStatsByModel: Record<string, { selected: number; executable: number; selectedDeletes: number }>
  setSelectedDeltaIndicesByModel: React.Dispatch<React.SetStateAction<SelectedDeltaIndicesByModel>>
  activeModel: string | null
  onSelectModel: (modelName: string | null) => void
  onCancel: () => void
  onExecute: () => void
  canExecute: boolean
  isLoading: boolean
  totalSelected: number
  totalExecutable: number
  selectedDeletes: number
  confirmDeletesChecked: boolean
  setConfirmDeletesChecked: (checked: boolean) => void
  errorCount: number
  ignoreErrors: boolean
  setIgnoreErrors: (checked: boolean) => void
}>) {
  const groupedModels = useMemo(() => {
    const bySchema = new Map<string, [string, ImportPreviewModelSummary][]> ()
    for (const entry of modelEntries) {
      const modelName = entry[0]
      const schema = MODEL_SCHEMA_MAP[resolveCanonicalModelKey(modelName)] ?? 'default'
      if (!bySchema.has(schema)) {
        bySchema.set(schema, [])
      }
      bySchema.get(schema)?.push(entry)
    }

    for (const entries of bySchema.values()) {
      entries.sort((a, b) => getModelLabel(a[0]).localeCompare(getModelLabel(b[0])))
    }

    const orderedSchemas = [...new Set([...SCHEMA_ORDER, ...bySchema.keys()])].filter((schema) => bySchema.has(schema))

    return orderedSchemas.map((schema) => ({ schema, entries: bySchema.get(schema) ?? [] }))
  }, [modelEntries])

  return (
    <Card className="flex min-h-[70vh] flex-col">
      <CardHeader className="space-y-3">
        <CardTitle>Import for {filename}</CardTitle>
        <div className="grid grid-cols-2 gap-2 text-sm">
          <div className="rounded border p-2">
            <div className="text-muted-foreground">Selected</div>
            <div className="text-lg font-semibold">{totalSelected}</div>
          </div>
          <div className="rounded border p-2">
            <div className="text-muted-foreground">Executable</div>
            <div className="text-lg font-semibold">{totalExecutable}</div>
          </div>
        </div>

        <div className="flex flex-wrap gap-2">
          <Button variant="outline" size="sm" onClick={() => setSelectedDeltaIndicesByModel(selectAll(modelEntries))}>
            Select All
          </Button>
          <Button variant="outline" size="sm" onClick={() => setSelectedDeltaIndicesByModel(deselectAll(modelEntries))}>
            Deselect All
          </Button>
          {activeModel && (
            <Button variant="outline" size="sm" onClick={() => onSelectModel(null)}>
              Back to Overview
            </Button>
          )}
        </div>
      </CardHeader>

      <CardContent className="flex min-h-0 flex-1 flex-col gap-3">
        <div className="min-h-0 flex-1 overflow-y-auto pr-1">
          {groupedModels.map((schemaGroup) => (
            <div key={schemaGroup.schema} className="mb-4">
              <p className="mb-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground">{schemaGroup.schema}</p>
              <div className="space-y-2">
                {schemaGroup.entries.map(([modelName, model]) => {
                  const selectedStats = selectedStatsByModel[modelName] ?? { selected: 0, executable: 0, selectedDeletes: 0 }
                  const isActive = activeModel === modelName

                  return (
                    <button
                      key={modelName}
                      type="button"
                      className={
                        'w-full rounded border p-2 text-left transition ' +
                        (isActive
                          ? 'border-blue-400 bg-blue-50 dark:border-blue-700 dark:bg-blue-950/40'
                          : 'border-border hover:bg-muted/30')
                      }
                      onClick={() => onSelectModel(modelName)}
                    >
                      <div className="flex items-center justify-between gap-2">
                        <span className="flex items-center gap-1.5 font-medium">
                          {getModelLabel(modelName)}
                          {model.errors > 0 && (
                            <Badge variant="outline" size="sm" className="text-red-700 border-red-300 dark:text-red-400 dark:border-red-700">
                              <AlertTriangleIcon className="size-3" />
                              !
                            </Badge>
                          )}
                        </span>
                        <span className="text-xs text-muted-foreground">
                          {selectedStats.selected}/{selectedStats.executable}
                        </span>
                      </div>
                      <div className="mt-2 flex flex-wrap gap-1">
                        <TooltipProvider>
                          <Tooltip>
                            <TooltipTrigger asChild>
                              <Badge variant="outline" size="sm" className={TYPE_BADGE_CLASSES.create}>
                                <PlusIcon className="size-3" />
                                {model.create}
                              </Badge>
                            </TooltipTrigger>
                            <TooltipContent>
                              <p>Rows that will be created.</p>
                            </TooltipContent>
                          </Tooltip>
                          <Tooltip>
                            <TooltipTrigger asChild>
                              <Badge variant="outline" size="sm" className={TYPE_BADGE_CLASSES.update}>
                                <PencilIcon className="size-3" />
                                {model.update}
                              </Badge>
                            </TooltipTrigger>
                            <TooltipContent>
                              <p>Rows that will be updated.</p>
                            </TooltipContent>
                          </Tooltip>
                          <Tooltip>
                            <TooltipTrigger asChild>
                              <Badge variant="outline" size="sm" className={TYPE_BADGE_CLASSES.delete}>
                                <Trash2Icon className="size-3" />
                                {model.delete}
                              </Badge>
                            </TooltipTrigger>
                            <TooltipContent>
                              <p>Rows that will be deleted.</p>
                            </TooltipContent>
                          </Tooltip>
                          <Tooltip>
                            <TooltipTrigger asChild>
                              <Badge variant="outline" size="sm" className={TYPE_BADGE_CLASSES.errors}>
                                <AlertTriangleIcon className="size-3" />
                                {model.errors}
                              </Badge>
                            </TooltipTrigger>
                            <TooltipContent>
                              <p>Rows with validation or parse errors.</p>
                            </TooltipContent>
                          </Tooltip>
                          <Tooltip>
                            <TooltipTrigger asChild>
                              <Badge variant="outline" size="sm" className={TYPE_BADGE_CLASSES.unchanged}>
                                <MinusIcon className="size-3" />
                                {model.unchanged}
                              </Badge>
                            </TooltipTrigger>
                            <TooltipContent>
                              <p>Rows with no data changes.</p>
                            </TooltipContent>
                          </Tooltip>
                        </TooltipProvider>
                      </div>
                    </button>
                  )
                })}
              </div>
            </div>
          ))}
        </div>

        <div className="space-y-3 border-t pt-3">
          {errorCount > 0 && (
            <div className="flex items-center gap-3">
              <Checkbox
                id="ignore-errors"
                checked={ignoreErrors}
                checkIcon="check"
                onChange={(event: React.ChangeEvent<HTMLInputElement>) => setIgnoreErrors(event.target.checked)}
              />
              <Label htmlFor="ignore-errors">Ignore {errorCount} error{errorCount === 1 ? '' : 's'}</Label>
            </div>
          )}

          {selectedDeletes > 0 && (
            <div className="flex items-center gap-2 rounded border border-red-300 bg-red-50 p-2 dark:border-red-900 dark:bg-red-950/20">
              <Checkbox
                id="confirm-deletes"
                checked={confirmDeletesChecked}
                checkIcon="check"
                onChange={(event: React.ChangeEvent<HTMLInputElement>) => setConfirmDeletesChecked(event.target.checked)}
              />
              <Label htmlFor="confirm-deletes">Confirm {selectedDeletes} delete{selectedDeletes === 1 ? '' : 's'}</Label>
            </div>
          )}

          <div className="flex gap-2">
            <Button variant="outline" onClick={onCancel} disabled={isLoading} className="flex-1">
              Cancel
            </Button>
            <Button onClick={onExecute} disabled={!canExecute || isLoading} className="flex-1">
              {isLoading ? 'Executing...' : 'Execute'}
            </Button>
          </div>
        </div>
      </CardContent>
    </Card>
  )
}

function OverviewTable({
  modelEntries,
  selectedStatsByModel,
  onOpenModel,
  onSelectAllModel,
  onDeselectAllModel,
}: Readonly<{
  modelEntries: [string, ImportPreviewModelSummary][]
  selectedStatsByModel: Record<string, { selected: number; executable: number; selectedDeletes: number }>
  onOpenModel: (modelName: string) => void
  onSelectAllModel: (modelName: string) => void
  onDeselectAllModel: (modelName: string) => void
}>) {
  return (
    <Card>
      <CardHeader>
        <CardTitle>Model Overview</CardTitle>
      </CardHeader>
      <CardContent className="overflow-x-auto">
        <table className="w-full min-w-[700px] text-sm">
          <thead>
            <tr className="border-b text-left text-muted-foreground">
              <th className="p-2">Model</th>
              <th className="p-2 text-right">Create</th>
              <th className="p-2 text-right">Update</th>
              <th className="p-2 text-right">Delete</th>
              <th className="p-2 text-right">Unchanged</th>
              <th className="p-2 text-right">Errors</th>
              <th className="p-2 text-right">Selected</th>
              <th className="p-2 text-right">Selection</th>
            </tr>
          </thead>
          <tbody>
            {modelEntries.map(([modelName, model]) => {
              const selected = selectedStatsByModel[modelName] ?? { selected: 0, executable: 0, selectedDeletes: 0 }
              return (
                <tr
                  key={modelName}
                  className="cursor-pointer border-b transition hover:bg-muted/20 last:border-b-0"
                  onClick={() => onOpenModel(modelName)}
                >
                  <td className="p-2 font-medium">{getModelLabel(modelName)}</td>
                  <td className="p-2 text-right">{model.create}</td>
                  <td className="p-2 text-right">{model.update}</td>
                  <td className="p-2 text-right">{model.delete}</td>
                  <td className="p-2 text-right">{model.unchanged}</td>
                  <td className="p-2 text-right font-medium text-red-600 dark:text-red-400">{model.errors}</td>
                  <td className="p-2 text-right font-semibold">
                    {selected.selected}/{selected.executable}
                  </td>
                  <td className="p-2 text-right">
                    <Button
                      size="sm"
                      variant="outline"
                      onClick={(event) => {
                        event.stopPropagation()
                        onSelectAllModel(modelName)
                      }}
                    >
                      Select All
                    </Button>
                    <Button
                      size="sm"
                      variant="outline"
                      className="ml-2"
                      onClick={(event) => {
                        event.stopPropagation()
                        onDeselectAllModel(modelName)
                      }}
                    >
                      Deselect All
                    </Button>
                  </td>
                </tr>
              )
            })}
          </tbody>
        </table>
      </CardContent>
    </Card>
  )
}

function ModelReviewPanel({
  modelName,
  model,
  selectedIndices,
  onSelectionChange,
  onBack,
}: Readonly<{
  modelName: string
  model: ImportPreviewModelSummary
  selectedIndices: number[]
  onSelectionChange: (indices: number[]) => void
  onBack: () => void
}>) {
  return (
    <Card>
      <CardHeader className="space-y-3">
        <div className="flex items-center justify-between gap-3">
          <CardTitle>{getModelLabel(modelName)}</CardTitle>
          <Button variant="outline" size="sm" onClick={onBack}>
            Back to Overview
          </Button>
        </div>
        <div className="flex flex-wrap gap-2">
          <Button size="sm" variant="outline" onClick={() => onSelectionChange(selectModel(model))}>
            Select Model
          </Button>
          <Button size="sm" variant="outline" onClick={() => onSelectionChange([])}>
            Deselect Model
          </Button>
        </div>
      </CardHeader>
      <CardContent>
        <ModelDataGrid
          modelName={modelName}
          items={model.items}
          selectedIndices={selectedIndices}
          onSelectionChange={onSelectionChange}
        />
      </CardContent>
    </Card>
  )
}


function ModelDataGrid({
  modelName,
  items,
  selectedIndices,
  onSelectionChange,
}: Readonly<{
  modelName: string
  items: ImportPreviewItem[]
  selectedIndices: number[]
  onSelectionChange: (indices: number[]) => void
}>) {
  const sorted = useMemo(
    () => [...items].sort((a, b) => TYPE_ORDER.indexOf(a.type) - TYPE_ORDER.indexOf(b.type)),
    [items],
  )

  const selectedSet = useMemo(() => new Set(selectedIndices), [selectedIndices])

  const fieldNames = useMemo(() => {
    const preferred = MODEL_FIELD_ORDER[resolveCanonicalModelKey(modelName)] ?? []
    if (preferred.length > 0) {
      return preferred
    }

    const fields: string[] = []
    const seen = new Set<string>()
    for (const item of sorted) {
      for (const key of Object.keys(item.input)) {
        if (!seen.has(key)) {
          seen.add(key)
          fields.push(key)
        }
      }
    }
    return fields
  }, [modelName, sorted])

  const columns = useMemo<ColumnDef<ImportPreviewItem>[]>(
    () => [
      {
        id: '_selected',
        header: 'Use',
        size: 74,
        enableResizing: false,
        meta: {
          cell: {
            variant: 'react-node' as const,
            render: ({ cell }) => {
              const row = cell.row.original as ImportPreviewItem
              if (!isExecutableItem(row) || typeof row.deltaIndex !== 'number') {
                return null
              }

              return (
                <Checkbox
                  checked={selectedSet.has(row.deltaIndex)}
                  checkIcon="check"
                  onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
                    const next = new Set(selectedSet)
                    if (event.target.checked) {
                      next.add(row.deltaIndex as number)
                    } else {
                      next.delete(row.deltaIndex as number)
                    }
                    onSelectionChange([...next].sort((a, b) => a - b)) // NOSONAR
                  }}
                />
              )
            },
          },
        },
      },
      {
        id: '_type',
        accessorKey: 'type',
        header: 'Type',
        size: 110,
        enableResizing: false,
        meta: {
          align: 'center' as const,
          cell: {
            variant: 'react-node' as const,
            render: ({ cell }) => {
              const rowType = (cell.row.original as ImportPreviewItem).type
              return (
                <div className="flex h-full w-full items-center justify-center overflow-hidden">
                  <Badge variant="outline" size="sm" className={"capitalize " + TYPE_BADGE_CLASSES[rowType]}>
                    {rowType}
                  </Badge>
                </div>
              )
            },
          },
        },
      },
      ...fieldNames.map(
        (field): ColumnDef<ImportPreviewItem> => ({
          id: field,
          accessorFn: (row: ImportPreviewItem) => row.input[field],
          header: formatFieldHeader(field),
          size: guessColumnSize(field, sorted),
          meta: {
            cell: {
              variant: 'react-node' as const,
              render: ({ cell }) => (
                <FieldCell item={cell.row.original as ImportPreviewItem} field={field} />
              ),
            },
          },
        }),
      ),
    ],
    [fieldNames, onSelectionChange, selectedSet, sorted],
  )

  const { table, ...dataGridProps } = useDataGrid({
    columns,
    data: sorted,
    initialState: {
      columnPinning: { left: ['_selected', '_type'] },
    },
  })

  const gridHeight = Math.min(760, sorted.length * 36 + 48)

  return <DataGrid {...dataGridProps} table={table} height={gridHeight} />
}

function FieldCell({ item, field }: Readonly<{ item: ImportPreviewItem; field: string }>) {
  const value = item.input[field]
  const formatted = formatValue(value)
  const cellClass = 'flex h-full w-full min-w-0 items-center overflow-hidden'
  const textClass = 'block w-full min-w-0 overflow-hidden text-ellipsis whitespace-nowrap'

  switch (item.type) {
    case 'unchanged':
      return (
        <div className={cellClass}>
          <span data-slot="grid-cell-content" className={textClass + ' text-muted-foreground'} title={formatted}>
            {formatted}
          </span>
        </div>
      )

    case 'create':
      return (
        <div className={cellClass}>
          <span
            data-slot="grid-cell-content"
            className={textClass + ' text-green-600 dark:text-green-400'}
            title={formatted}
          >
            {formatted}
          </span>
        </div>
      )

    case 'delete':
      return (
        <div className={cellClass}>
          <span
            data-slot="grid-cell-content"
            className={textClass + ' line-through text-red-600 dark:text-red-400'}
            title={formatted}
          >
            {formatted}
          </span>
        </div>
      )

    case 'update': {
      if (item.delta && field in item.delta) {
        const oldNew = item.delta[field]
        return (
          <div className={cellClass}>
            <span
              data-slot="grid-cell-content"
              className="block w-full min-w-0 truncate text-sm"
              title={formatValue(oldNew.old) + ' → ' + formatValue(oldNew.new)}
            >
              <span className="line-through text-red-600 opacity-70 dark:text-red-400">{formatValue(oldNew.old)}</span>
              <span className="text-xs text-muted-foreground"> → </span>
              <span className="font-medium text-green-600 dark:text-green-400">{formatValue(oldNew.new)}</span>
            </span>
          </div>
        )
      }
      return (
        <div className={cellClass}>
          <span data-slot="grid-cell-content" className={textClass + ' text-muted-foreground'} title={formatted}>
            {formatted}
          </span>
        </div>
      )
    }

    case 'errors': {
      const errorForField = getFieldError(item.errors, field)
      if (errorForField) {
        return (
          <div className={cellClass}>
            <TooltipProvider>
              <Tooltip>
                <TooltipTrigger asChild>
                  <span
                    data-slot="grid-cell-content"
                    className="block w-full min-w-0 cursor-help truncate underline decoration-wavy text-red-600 dark:text-red-400"
                    title={formatted || '(empty)'}
                  >
                    {formatted || '(empty)'}
                  </span>
                </TooltipTrigger>
                <TooltipContent>
                  <p>{errorForField}</p>
                </TooltipContent>
              </Tooltip>
            </TooltipProvider>
          </div>
        )
      }
      return (
        <div className={cellClass}>
          <span data-slot="grid-cell-content" className={textClass + ' text-muted-foreground'} title={formatted}>
            {formatted}
          </span>
        </div>
      )
    }
  }
}

function isExecutableItem(item: ImportPreviewItem): boolean {
  return EXECUTABLE_TYPES.has(item.type)
}

function buildDefaultSelection(models: Record<string, ImportPreviewModelSummary>): SelectedDeltaIndicesByModel {
  const selection: SelectedDeltaIndicesByModel = {}

  for (const [modelName, model] of Object.entries(models)) {
    selection[modelName] = model.items
      .filter((item) => isExecutableItem(item) && typeof item.deltaIndex === 'number')
      .map((item) => item.deltaIndex as number)
      .sort((a, b) => a - b)
  }

  return selection
}

function selectionEquals(a: SelectedDeltaIndicesByModel, b: SelectedDeltaIndicesByModel): boolean {
  const keys = new Set([...Object.keys(a), ...Object.keys(b)])
  for (const key of keys) {
    const left = [...(a[key] ?? [])].sort((x, y) => x - y)
    const right = [...(b[key] ?? [])].sort((x, y) => x - y)
    if (left.length !== right.length) {
      return false
    }
    for (let i = 0; i < left.length; i++) {
      if (left[i] !== right[i]) {
        return false
      }
    }
  }
  return true
}

function selectModel(model: ImportPreviewModelSummary): number[] {
  return model.items
    .filter((item) => isExecutableItem(item) && typeof item.deltaIndex === 'number')
    .map((item) => item.deltaIndex as number)
    .sort((a, b) => a - b)
}

function selectAll(modelEntries: [string, ImportPreviewModelSummary][]): SelectedDeltaIndicesByModel {
  const next: SelectedDeltaIndicesByModel = {}
  for (const [modelName, model] of modelEntries) {
    next[modelName] = selectModel(model)
  }
  return next
}

function deselectAll(modelEntries: [string, ImportPreviewModelSummary][]): SelectedDeltaIndicesByModel {
  const next: SelectedDeltaIndicesByModel = {}
  for (const [modelName] of modelEntries) {
    next[modelName] = []
  }
  return next
}

function getModelLabel(modelName: string): string {
  const canonicalModelKey = resolveCanonicalModelKey(modelName)
  return MODEL_LABEL_MAP[canonicalModelKey] ?? modelName
}

function resolveCanonicalModelKey(modelName: string): string {
  if (MODEL_LABEL_MAP[modelName] || MODEL_SCHEMA_MAP[modelName] || MODEL_FIELD_ORDER[modelName]) {
    return modelName
  }

  const normalizedModelName = modelName.toLowerCase()
  for (const [key, label] of Object.entries(MODEL_LABEL_MAP)) {
    if (key.toLowerCase() === normalizedModelName || label.toLowerCase() === normalizedModelName) {
      return key
    }
  }

  return modelName
}

function getFieldError(errors: unknown[] | undefined, field: string): string | null {
  if (!errors) {
    return null
  }

  let genericParseError: string | null = null
  for (const err of errors) {
    const fieldError = getFieldLevelError(err, field)
    if (fieldError) {
      return fieldError
    }

    const parseErrorMessage = getParseErrorMessage(err)
    if (!parseErrorMessage) {
      continue
    }

    if (parseErrorMentionsField(parseErrorMessage, field)) {
      return parseErrorMessage
    }

    if (!genericParseError) {
      genericParseError = parseErrorMessage
    }
  }

  return genericParseError
}

function getFieldLevelError(err: unknown, field: string): string | null {
  if (typeof err !== 'object' || err === null || !('fieldName' in err)) {
    return null
  }
  const errObj = err as { fieldName: string; error: string; message?: string }
  if (errObj.fieldName !== field) {
    return null
  }
  return errObj.message ?? errObj.error
}

function getParseErrorMessage(err: unknown): string | null {
  if (typeof err !== 'object' || err === null || !('error' in err)) {
    return null
  }
  if ((err as { error?: unknown }).error !== 'parse-error') {
    return null
  }
  const messageValue = 'message' in err ? (err as { message?: unknown }).message : undefined
  return typeof messageValue === 'string' ? messageValue : null
}

function parseErrorMentionsField(message: string, field: string): boolean {
  return (
    message.startsWith('Field "' + field + '":') ||
    message.startsWith('Field "' + field + '."') ||
    message.includes('."' + field + '".') ||
    message.includes('.' + field + ':')
  )
}

function formatFieldHeader(field: string): string {
  const withCaseSpacing = field.replaceAll(/([a-z])([A-Z])/g, '$1 $2')
  const normalized = withCaseSpacing.replaceAll('_', ' ').replaceAll('-', ' ')
  return normalized
    .split(/\\s+/)
    .filter(Boolean)
    .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
    .join(' ')
}

function formatValue(value: unknown): string {
  if (value === null) {
    return 'null'
  }
  if (value === undefined) {
    return ''
  }
  if (typeof value === 'string') {
    return value
  }
  if (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint') {
    return \`\${value}\` // NOSONAR
  }
  if (typeof value === 'symbol') {
    return value.toString()
  }
  if (typeof value === 'object') {
    return formatObjectValue(value as Record<string, unknown>)
  }
  return String(value) // NOSONAR
}

function formatObjectValue(obj: Record<string, unknown>): string {
  const serialized = safeJsonStringify(obj)
  if (serialized) {
    return truncate(serialized, 140)
  }

  const keys = Object.keys(obj).slice(0, 8)
  if (keys.length === 0) {
    return '{}'
  }

  const parts: string[] = []
  for (const key of keys) {
    const val = obj[key]
    if (val !== null && val !== undefined && val !== '') {
      const formatted = typeof val === 'object' ? '{...}' : formatValue(val)
      parts.push(key + ': ' + formatted)
    }
  }

  return truncate(parts.join(', '), 140)
}

function safeJsonStringify(value: unknown): string | null {
  try {
    return JSON.stringify(value)
  } catch {
    return null
  }
}

function truncate(value: string, maxLength: number): string {
  if (value.length <= maxLength) {
    return value
  }
  return value.slice(0, maxLength - 3) + '...'
}

function guessColumnSize(field: string, items: ImportPreviewItem[]): number {
  const sample = items.slice(0, 5)
  const values = sample.map((item) => item.input[field])

  for (const val of values) {
    if (val === undefined || val === null) {
      continue
    }
    if (typeof val === 'object') {
      return 240
    }
    const str = String(val)
    if (/^[0-9a-f]{8}-[0-9a-f]{4}-/.test(str)) {
      return 280
    }
    if (/^\\d{4}-\\d{2}-\\d{2}T/.test(str)) {
      return 220
    }
  }

  const lower = field.toLowerCase()
  if (lower.includes('id')) {
    return 280
  }
  if (lower.includes('date') || lower.includes('at')) {
    return 220
  }

  return 180
}
`;
}
//# sourceMappingURL=import-review-page-review-stage.generator.js.map