/**
 * Client-safe module registry — no loadData, no cloudflare:workers.
 *
 * Auto-discovers modules via Vite glob (Component, ConfigEditor, config only).
 * The loadData.ts glob is intentionally absent — this is the boundary enforcement.
 *
 * Import this in React islands (PageRenderer, admin-page-organizer).
 * Never import registry.ts on the client — it pulls loadData → env → cloudflare:workers.
 */
import type { z } from 'zod';
import { createElement } from 'react';
import type { ClientModuleDef } from './types';
import { BasicRowConfigEditor } from './modules/_shared/BasicRowConfigEditor';

type ConfigMod = {
  type: string;
  category: ClientModuleDef<unknown>['category'];
  labelKey: string;
  defaultConfig: unknown;
  configSchema: z.ZodType<unknown>;
};
type ComponentMod = { Component: ClientModuleDef<unknown>['Component'] };
type EditorMod = { ConfigEditor: ClientModuleDef<unknown>['ConfigEditor'] };

const configMods = import.meta.glob<ConfigMod>('./modules/*/config.ts', { eager: true });
const componentMods = import.meta.glob<ComponentMod>('./modules/*/Component.tsx', { eager: true });
const editorMods = import.meta.glob<EditorMod>('./modules/*/ConfigEditor.tsx', { eager: true });
const BASIC_ROW_EDITOR_FOLDERS = new Set([
  'deal-row-affinity',
  'deal-row-for-you',
  'deal-row-group-deals',
  'deal-row-hot-deals',
  'deal-row-near-you',
  'deal-row-whats-left',
]);

function isBasicRowConfig(
  config: unknown,
): config is { title: { he: string; en: string }; limit: number } {
  if (typeof config !== 'object' || config === null) return false;
  const value = Object.fromEntries(Object.entries(config));
  if (typeof value.limit !== 'number' || typeof value.title !== 'object' || value.title === null) {
    return false;
  }
  const title = Object.fromEntries(Object.entries(value.title));
  return typeof title.he === 'string' && typeof title.en === 'string';
}

const basicRowConfigEditor: ClientModuleDef<unknown>['ConfigEditor'] = ({ config, onChange }) => {
  if (!isBasicRowConfig(config)) return null;
  return createElement(BasicRowConfigEditor, { config, onChange });
};

export const CLIENT_MODULE_REGISTRY: Record<string, ClientModuleDef<unknown>> = {};

for (const [configPath, cfg] of Object.entries(configMods)) {
  const folder = configPath.replace('./modules/', '').replace('/config.ts', '');
  const cmpMod = componentMods[`./modules/${folder}/Component.tsx`];
  const editorMod = editorMods[`./modules/${folder}/ConfigEditor.tsx`];
  const ConfigEditor =
    editorMod?.ConfigEditor ??
    (BASIC_ROW_EDITOR_FOLDERS.has(folder) ? basicRowConfigEditor : undefined);

  if (!cmpMod || !ConfigEditor) {
    throw new Error(
      `[page-layout] Module "${folder}" is missing Component.tsx or ConfigEditor.tsx`,
    );
  }

  CLIENT_MODULE_REGISTRY[cfg.type] = {
    type: cfg.type,
    category: cfg.category,
    labelKey: cfg.labelKey,
    defaultConfig: cfg.defaultConfig,
    configSchema: cfg.configSchema,
    Component: cmpMod.Component,
    ConfigEditor,
  };
}
