import {__, sprintf} from '@wordpress/i18n';
import {forwardRef} from '@wordpress/element';

import TextField from './form-fields/TextField';
import SelectField from './form-fields/SelectField';
import ToggleField from './form-fields/ToggleField';
import TextAreaField from './form-fields/TextAreaField';
import HeadingField from './form-fields/HeadingField';
import ButtonField from './form-fields/ButtonField';
import HtmlField from './form-fields/HtmlField';
import ImageUploadField from './form-fields/ImageUploadField';
import RadioField from './form-fields/RadioField';
import PositioningField from './form-fields/PositioningField';
import SpacingField from './form-fields/SpacingField';
import ConditionsField from './form-fields/ConditionsField';
import ButtonGroupField from './form-fields/ButtonGroupField';
import ImageGroupField from './form-fields/ImageGroupField';
import HtmlEditorField from '../modal/src/components/editor/HtmlEditorField';
import TokenSelectField from './form-fields/TokenSelectField';
import TokenInputField from './form-fields/TokenInputField';
import AssignmentField from './form-fields/AssignmentField';
import SchedulePeriodField from './form-fields/SchedulePeriodField';
import ScheduleTimeField from './form-fields/ScheduleTimeField';
import CheckboxButtonGroupField from './form-fields/CheckboxButtonGroupField';
import GroupAdsAssignmentField from './form-fields/GroupAdsAssignmentField';
import FieldControl from './components/FieldControl';
import Html5UploadField from './form-fields/Html5UploadField';
import ColorPickerField from './form-fields/ColorPickerField';
import LinkMaskingPreview from './components/LinkMaskingPreview';

/**

 * Checks whether all dependencies (depends_on) for a field are fulfilled.
 * @param {object} field - The field object containing the ‘depends_on’ rules.
 * @param {object} allMetaData - The entire metadata object.
 * @param allFields
 *
 * @returns {boolean} - True if the field should be displayed, otherwise false.
 */
const checkDependencies = ( field, allMetaData, allFields = [] ) => {
	if ( !field.depends_on ) {
		return true;
	}

	const rules = Array.isArray( field.depends_on )
		? field.depends_on
		: [field.depends_on];

	// All rules have to be correct (AND-logic)
	for ( const rule of rules ) {
		const {field_id, operator, value: expectedValue} = rule;

		// Get the actual value of the field
		let actualValue;
		if ( field_id.includes( '.' ) ) {
			const keys = field_id.split( '.' );
			actualValue = allMetaData[keys[0]] ? allMetaData[keys[0]][keys[1]] : undefined;
		} else {
			actualValue = allMetaData[field_id];
		}

		if ( actualValue === undefined || actualValue === null ) {

			// Find the referenced field (e.g., ‘show_debug_options’) in the configurations.
			const targetField = allFields.find( f => f.id === field_id );

			if ( targetField && targetField.default !== undefined ) {
				actualValue = targetField.default;
			} else {
				actualValue = ''; // fallback, if there are no default values at all
			}
		}

		const normalizeValue = ( val ) => {
			if ( val === true ) {
				return '1';
			}
			if ( val === false ) {
				return '0';
			}
			return String( val );
		};

		const safeActual = normalizeValue( actualValue );
		const safeExpected = normalizeValue( expectedValue );

		// Perform the check based on the operator
		let isMet = false;
		switch ( operator ) {
			case 'is':
				isMet = (safeActual === safeExpected);
				break;
			case 'is_not':
				isMet = (safeActual !== safeExpected);
				break;
			case 'greater_than':
				isMet = (Number( actualValue ) > Number( expectedValue ));
				break;
			case 'smaller_than':
				isMet = (Number( actualValue ) < Number( expectedValue ));
				break;
			default:
				console.warn( `AdPresso FieldRenderer: Unknown dependency operator "${operator}"` );
				isMet = false;
		}

		// If a single rule is not met, hide the field.
		if ( !isMet ) {
			return false;
		}
	}

	// All rules have been fulfilled
	return true;
};

/**
 * The FieldRenderer decides which specific field component should be rendered based on field.type.
 * It simply passes on the props (field, value, onChange).
 */
const FieldRenderer = forwardRef( ( {field, onDataChange, allMetaData, availableConditions, entityData, onSetDirty, variantClass, fields}, ref ) => {

	const value = field.id === 'content'
		? entityData.content // Take the top-level-value for the content field
		: (field.meta_key    // Else use the meta field logic
		? allMetaData[field.meta_key]?.[field.id]
		: allMetaData[field.id]) ?? field.default;

	const handleChange = ( fieldId, newValue ) => {
		onDataChange( fieldId, newValue, field.meta_key || null );
	};

	const dependenciesMet = checkDependencies( field, allMetaData, fields );

	if ( !dependenciesMet ) {
		return null;
	}

	const wrapperClassName = `adpresso-field-type-${field.type} ${field.premium ? 'is-premium' : ''}`;

	const Wrapper = ( {children} ) => (
		<FieldControl label={field.label} help={field.description} premium={field.premium} id={field.id} className={`${wrapperClassName} ${field.depends_on ? 'adpresso-field-control__child' : ''}`.trim()}>
			{children}
		</FieldControl>
	);

	const renderWithWrapper = ( children ) => (
		<FieldControl label={field.label} help={field.description} premium={field.premium} id={field.id} link={field.link} className={`${wrapperClassName} ${field.depends_on ? 'adpresso-field-control__child' : ''}`.trim()}>
			{children}
		</FieldControl>
	);

	switch ( field.type ) {
		case 'text':
		case 'url':
		case 'number':
			return <TextField field={field} value={value} onChange={handleChange} variantClass={variantClass}/>;

		case 'select':
			return <SelectField field={field} value={value} variantClass={variantClass} onChange={handleChange}/>;

		case 'checkbox': // replace checkboxes with toggles
		case 'toggle':
			return <ToggleField field={field} value={value} onChange={handleChange}/>;

		case 'textarea':
			return <TextAreaField field={field} premium={field.premium} value={value} onChange={handleChange}/>;

		case 'heading':
			return <HeadingField field={field}/>;

		case 'token_select':
			return renderWithWrapper(<TokenSelectField field={field} value={value} onChange={handleChange} variantClass={variantClass}/>);

		case 'token_input':
			return <TokenInputField field={field} value={value} onChange={handleChange}/>;

		case 'button':
			return <ButtonField className="adpresso-chip" field={field}/>;

		case 'button_group':
			return <ButtonGroupField field={field} value={value} onChange={handleChange}/>;

		case 'checkbox_button_group':
			return <CheckboxButtonGroupField field={field} value={value} onChange={handleChange}/>;

		case 'color_picker':
			return <ColorPickerField field={field} value={value} onChange={handleChange}/>;

		case 'image_group':
			return <ImageGroupField field={field} value={value} onChange={handleChange}/>;

		case 'div':
		case 'html-content':
			return <HtmlField field={field} value={value}/>;

		case 'html-editor':
			return <HtmlEditorField field={field} value={value} onChange={handleChange} allMetaData={allMetaData}/>;

		case 'image_upload':
			return renderWithWrapper(<ImageUploadField field={field} value={value} onChange={handleChange}/>);

		case 'link_preview':
			return renderWithWrapper(<LinkMaskingPreview isMaskingActive={true} allMetaData={allMetaData}/>);

		case 'html5-upload':
			return renderWithWrapper(<Html5UploadField field={field} value={value} onChange={handleChange}/>);

		case 'radio':
			return <RadioField field={field} value={value} onChange={handleChange}/>;

		case 'positioning': {
			const layoutSettings = allMetaData?.layout_settings ?? {};
			const currentPosition =
				(layoutSettings.position ?? allMetaData?.position ?? 'none');

			// Normalise legacy data
			const normalize = ( v ) => String( v || '' ).replace( '-', '_' );

			const handlePositionChange = ( newPos ) => {
				const pos = normalize( newPos );

				// save everything in layout_settings
				const nextLayout = {...layoutSettings, position: pos};
				onDataChange( 'layout_settings', nextLayout );
				onDataChange( 'position', pos );
			};

			return (
				<PositioningField
					field={field}
					value={normalize( currentPosition )}
					onChange={handlePositionChange}
				/>
			);
		}

		case 'spacing': {
			const layoutSettings = allMetaData?.layout_settings || {};
			const isCentered = layoutSettings.position === 'center_nofloat';
			const spacingValue = layoutSettings.margin || {}; // Fallback auf leeres Objekt

			const handleSpacingChange = ( direction, newDirectionValue ) => {
				// Create the new Layout_settings object
				const newLayoutSettings = {
					...layoutSettings, // keep other values like 'positioning'
					margin: {
						...spacingValue,
						[direction]: newDirectionValue
					}
				};

				onDataChange( 'layout_settings', newLayoutSettings );
			};

			return renderWithWrapper(
				<SpacingField
					field={field}
					value={spacingValue}
					onChange={handleSpacingChange}
					isReadonly={isCentered}
				/>
			);
		}

		case 'assignment':
			return <AssignmentField
				ref={ref}
				field={field}
				entityData={entityData}
				onSetDirty={onSetDirty}
			/>;

		case 'group_ads_assignment':
			return <GroupAdsAssignmentField field={field} value={value} onChange={onDataChange} allMetaData={allMetaData}/>;

		case 'conditions':
			return renderWithWrapper(<ConditionsField field={field} value={value} onChange={handleChange} availableConditions={availableConditions}/>);

		case 'schedule_time':
			return renderWithWrapper(
				<ScheduleTimeField
					field={field}
					allMetaData={allMetaData}
					onDataChange={onDataChange}
				/>
			);

		case 'schedule_period':
			return renderWithWrapper(
				<SchedulePeriodField
					field={field}
					allMetaData={allMetaData}
					onDataChange={onDataChange}
				/>
			);

		default:
			return <div className="adpresso-text adpresso-color-destructive">{sprintf( __( 'Unknown field type: %s', 'adpresso' ), field.type )}</div>;
	}
} );

export default FieldRenderer;
