/**
 * Framework extension registry — the seam that keeps cliq-ui domain-agnostic.
 *
 * Host plugins (loaded as a separate bundle that depends on the cliqthemes-ui-app
 * script handle) register their screens / builder types / widgets on
 * `window.cliqUI` at eval time. cliq-ui loads first and defines this singleton;
 * the host bundle runs next (before cliq-ui's domReady mount) and registers; the
 * App/Builder read the merged registries at render. React is a shared external
 * global, so components cross the bundle boundary safely.
 */
import queryContext from './queryContext';
import hooks from '../../shared/hooks';

const createRegistry = () => {
	const screens = {};
	const builderTypes = [];
	const widgets = {};
	const toolbarItems = [];
	const fields = {};
	const controlTypes = {};
	let bannerArt = null;
	let bannerBrand = null;

	const api = {
		version: '1.0.0',

		// Admin screens: registerScreen('leads', { label, icon, Component, order }).
		registerScreen( id, def ) {
			if ( id && def && def.Component ) screens[ id ] = { id, ...def };
			return api;
		},
		screens() {
			return screens;
		},

		// Builder "New" types: { purpose, mode, label, icon, desc }.
		registerBuilderType( def ) {
			if ( def && def.purpose ) builderTypes.push( def );
			return api;
		},
		builderTypes() {
			return builderTypes;
		},

		// Builder widgets: { value, label, icon, defaults, Inspector, Preview }.
		registerWidget( def ) {
			if ( def && def.value ) widgets[ def.value ] = def;
			return api;
		},
		widgets() {
			return widgets;
		},

		// Custom field types: registerField('map', MapFieldComponent). Host-registered
		// types extend/override the core field registry, so domain fields (maps,
		// markers, …) live in the host bundle, not the framework.
		registerField( type, Component ) {
			if ( type && Component ) fields[ type ] = Component;
			return api;
		},
		fields() {
			return fields;
		},

		// Builder control renderers for genuinely interactive controls that
		// cannot be represented by the standard data-only control set.
		registerControlType( type, Component ) {
			if ( type && Component ) controlTypes[ type ] = Component;
			return api;
		},
		controlTypes() {
			return controlTypes;
		},

		// Banner toolbar controls: registerToolbarItem({ id, Component, order }).
		registerToolbarItem( def ) {
			if ( def && def.Component ) toolbarItems.push( { order: 10, ...def } );
			return api;
		},
		toolbarItems() {
			return [ ...toolbarItems ].sort( ( a, b ) => ( a.order ?? 10 ) - ( b.order ?? 10 ) );
		},

		// Decorative banner artwork (a component) — host-supplied, since it's domain
		// branding. cliq-ui ships none; the banner simply has no motif if unregistered.
		registerBannerArt( Component ) {
			if ( Component ) bannerArt = Component;
			return api;
		},
		bannerArt() {
			return bannerArt;
		},

		// Optional host-specific banner identity. When registered, this replaces
		// the framework's generic icon + product/byline treatment.
		registerBannerBrand( Component ) {
			if ( Component ) bannerBrand = Component;
			return api;
		},
		bannerBrand() {
			return bannerBrand;
		},

		// Generic query-context channel (host-defined keys appended to fetches).
		queryContext,

		// JS hook bus (filters/actions) shared with the frontend — the runtime
		// extension seam. e.g. cliqUI.hooks.addFilter('cliqui.token_value', …).
		hooks,

		// Shared framework UI exposed to host inspectors/previews (filled in index.js).
		components: {},
	};

	return api;
};

const registry =
	( typeof window !== 'undefined' && window.cliqUI ) || createRegistry();

if ( typeof window !== 'undefined' ) {
	window.cliqUI = registry;
}

export default registry;
