/**
 * Shared field control renderer for Gutenberg + admin ContentEditor.
 */
import { TextControl, ToggleControl } from '@wordpress/components';
import { createElement } from '@wordpress/element';
import { __, sprintf } from '@wordpress/i18n';
import ElementsOrderField from './ElementsOrderField';
import LinkField from './LinkField';
import MediaField from './MediaField';
import RepeaterField from './RepeaterField';
import TagField from './TagField';
import ButtonIconPicker from './ButtonIconPicker';
import SearchableSelect from '../SearchableSelect';
import TextWysiwygField, { isTextWysiwygType } from './TextWysiwygField';
import { isInlineEditEnabled } from '../../shared/previewContentEdit';
/**
 * Normalize select options from field schema.
 *
 * @param {object} field
 * @return {Array<{ label: string, value: string }>}
 */
function selectOptions( field ) {
	const raw = Array.isArray( field?.options ) ? field.options : [];
	return raw
		.map( ( opt ) => {
			if ( typeof opt === 'string' ) {
				return { label: opt, value: opt };
			}
			if ( opt && typeof opt === 'object' ) {
				const value = String( opt.value ?? opt.id ?? '' );
				const label = String( opt.label ?? opt.name ?? value );
				return value ? { label, value } : null;
			}
			return null;
		} )
		.filter( Boolean );
}

/**
 * @param {object}   props
 * @param {object}   props.field
 * @param {*}        props.value
 * @param {Function} props.onChange
 * @param {object}   [props.options]
 * @param {Function} [props.renderRichText] optional rich text renderer for wysiwyg
 * @param {Function} [props.renderFallback] optional fallback for unknown / text types
 */
export default function SchemaFieldControl( {
	field,
	value,
	onChange,
	options = {},
	renderRichText,
	renderFallback,
} ) {
	if ( ! field?.key ) {
		return null;
	}

	const type = field.type || 'text';
	const visibilityKeys = Array.isArray( options.visibilityKeys )
		? options.visibilityKeys
		: [];
	const visibilityBp =
		options.visibilityBreakpoint === 'tablet' ||
		options.visibilityBreakpoint === 'mobile'
			? options.visibilityBreakpoint
			: 'desktop';
	/*
	 * Column media (image-left / image-right / slider columns): hide/show only
	 * on tablet & mobile — desktop always keeps the media column.
	 */
	const keyBreakpoints =
		options.visibilityKeyBreakpoints &&
		typeof options.visibilityKeyBreakpoints === 'object'
			? options.visibilityKeyBreakpoints[ field.key ]
			: null;
	const breakpointAllowsVisibility =
		! Array.isArray( keyBreakpoints ) ||
		keyBreakpoints.includes( visibilityBp );
	const canToggleVisibility =
		typeof options.onVisibilityChange === 'function' &&
		visibilityKeys.includes( field.key ) &&
		breakpointAllowsVisibility;
	const isVisible =
		! canToggleVisibility ||
		( options.visibility &&
		typeof options.visibility === 'object' &&
		Object.prototype.hasOwnProperty.call( options.visibility, field.key )
			? options.visibility[ field.key ] !== false
			: true );
	const visibilityBpLabel =
		visibilityBp === 'tablet'
			? __( 'Tablet', 'joc-blockora-morph' )
			: visibilityBp === 'mobile'
			? __( 'Mobile', 'joc-blockora-morph' )
			: __( 'Desktop', 'joc-blockora-morph' );

	const hasTagControl =
		options.tagField && typeof options.onTagChange === 'function';
	const useCompactHead = canToggleVisibility || hasTagControl;

	const fieldForControl = useCompactHead ? { ...field, label: '' } : field;

	let control = null;
	/** When true, do not fall back to a plain TextControl for this field. */
	let omitValueControl = false;

	if ( type === 'link' ) {
		control = createElement( LinkField, {
			label: fieldForControl.label,
			value,
			onChange,
		} );
	} else if ( type === 'media' ) {
		control = createElement( MediaField, {
			label: fieldForControl.label,
			value,
			onChange,
			field: fieldForControl,
		} );
	} else if ( type === 'repeater' ) {
		control = createElement( RepeaterField, {
			label: fieldForControl.label,
			value,
			onChange,
			field: fieldForControl,
			onEditStyles:
				typeof options.onEditButtonStyles === 'function'
					? ( index ) => options.onEditButtonStyles( field.key, index )
					: undefined,
			allowManageButtonItems:
				options.allowManageButtonItems !== false,
			onFocusItem:
				typeof options.onFocusItem === 'function'
					? options.onFocusItem
					: undefined,
			previewScope: options.previewScope || null,
		} );
	} else if ( type === 'elementsOrder' ) {
		if ( options.hideElementsOrder ) {
			return null;
		}
		return createElement( ElementsOrderField, {
			label: field.label,
			value,
			onChange,
			field,
			appliesGlobally: options.appliesGlobally !== false,
		} );
	} else if ( type === 'tag' ) {
		// Standalone tag (no parent content field) — still compact popover.
		control = createElement( TagField, {
			label: fieldForControl.label || field.label,
			value,
			onChange,
			field: fieldForControl,
		} );
	} else if ( type === 'toggle' || type === 'boolean' ) {
		control = createElement( ToggleControl, {
			label: fieldForControl.label,
			checked: value === true || value === 1 || value === '1' || value === 'true',
			onChange: ( next ) => onChange( Boolean( next ) ),
			__nextHasNoMarginBottom: true,
		} );
	} else if ( type === 'number' ) {
		control = createElement( TextControl, {
			label: fieldForControl.label,
			type: 'number',
			value: value === '' || value == null ? '' : String( value ),
			onChange: ( next ) => {
				if ( next === '' || next == null ) {
					onChange( '' );
					return;
				}
				const n = Number( next );
				onChange( Number.isFinite( n ) ? n : next );
			},
			min: field.min != null ? Number( field.min ) : undefined,
			max: field.max != null ? Number( field.max ) : undefined,
			step: field.step != null ? Number( field.step ) : undefined,
			help: field.help || undefined,
			__nextHasNoMarginBottom: true,
			__next40pxDefaultSize: true,
		} );
	} else if ( type === 'select' ) {
		const optionsList = selectOptions( field );
		const fallback = String(
			field.default ?? optionsList[ 0 ]?.value ?? ''
		);
		control = createElement( SearchableSelect, {
			label: fieldForControl.label,
			value: value != null && value !== '' ? String( value ) : fallback,
			options: optionsList,
			onChange: ( next ) => onChange( next || fallback ),
			help: field.help || undefined,
		} );
	} else if ( type === 'dashicon' || type === 'icon' ) {
		control = createElement(
			'div',
			{ className: 'bm-field bm-field--dashicon' },
			fieldForControl.label
				? createElement(
						'span',
						{ className: 'bm-field-label' },
						fieldForControl.label
				  )
				: null,
			createElement( ButtonIconPicker, {
				value: value || '',
				onChange,
			} )
		);
	} else if ( isTextWysiwygType( type ) ) {
		// Preview-inline content: side panel keeps visibility / tag only.
		if (
			options.hideContentEditor === true ||
			( options.hideContentEditor !== false &&
				isInlineEditEnabled( field ) )
		) {
			control = null;
			omitValueControl = true;
		} else {
			control = createElement( TextWysiwygField, {
				label: fieldForControl.label,
				value: value || '',
				onChange,
				help: field.help || '',
				hideLabel: useCompactHead,
				field,
				allowedCommand:
					field.allowedCommand ??
					field.allowedCommands ??
					undefined,
				disableAdvanceEditor:
					field.disableAdvanceEditor ??
					field.disableAdvancedEditor ??
					undefined,
			} );
		}
	}

	if ( ! control && ! omitValueControl && typeof renderFallback === 'function' ) {
		control = renderFallback( {
			field: fieldForControl,
			value,
			onChange,
			type,
		} );
	}

	if ( ! control && ! omitValueControl ) {
		control = createElement( TextControl, {
			label: fieldForControl.label,
			type: type === 'url' ? 'url' : 'text',
			value: value || '',
			onChange,
		} );
	}

	if ( ! useCompactHead ) {
		return control;
	}

	// Visibility / tag chrome with no value editor (preview-edited content).
	if ( omitValueControl && ! canToggleVisibility && ! hasTagControl ) {
		return null;
	}

	const tagButton = hasTagControl
		? createElement( TagField, {
				label: options.tagField.label,
				value: options.tagValue,
				onChange: options.onTagChange,
				field: options.tagField,
		  } )
		: null;

	const visibilityToggle = canToggleVisibility
		? createElement( ToggleControl, {
				className:
					'bm-field-visibility-head__toggle' +
					( isVisible ? '' : ' is-hidden' ),
				checked: isVisible,
				onChange: ( next ) => {
					options.onVisibilityChange( {
						...( options.visibility &&
						typeof options.visibility === 'object'
							? options.visibility
							: {} ),
						[ field.key ]: Boolean( next ),
					} );
				},
				label: createElement(
					'span',
					{
						className: 'bm-field-visibility-head__toggle-label',
					},
					createElement( 'span', {
						className:
							'dashicons dashicons-' +
							( isVisible ? 'visibility' : 'hidden' ),
						'aria-hidden': true,
					} ),
					createElement(
						'span',
						{ className: 'bm-field-visibility-head__toggle-bp' },
						sprintf(
							/* translators: %s: Desktop, Tablet, or Mobile */
							__( '· %s', 'joc-blockora-morph' ),
							visibilityBpLabel
						)
					)
				),
				__nextHasNoMarginBottom: true,
		  } )
		: null;

	return createElement(
		'div',
		{
			className: [
				'bm-field-wrap',
				'bm-field-wrap--visibility',
				isVisible ? '' : 'is-hidden-element',
			]
				.filter( Boolean )
				.join( ' ' ),
		},
		createElement(
			'div',
			{ className: 'bm-field-visibility-head' },
			createElement(
				'span',
				{ className: 'bm-field-visibility-head__label' },
				field.label || field.key
			),
			createElement(
				'div',
				{ className: 'bm-field-visibility-head__actions' },
				tagButton,
				visibilityToggle
			)
		),
		control
	);
}
