/**
 * The Settings component for the Genesis Blocks settings page.
 *
 * Gets and sets data via the genesis-blocks/global-settings data store.
 *
 * @since   1.0.0
 * @author  StudioPress
 * @license GPL-2.0-or-later
 */

/**
 * WordPress dependencies
 */
import { __ } from '@wordpress/i18n';
import { compose } from '@wordpress/compose';
import { TabPanel, SlotFillProvider, Slot } from '@wordpress/components';
import { dispatch, select, withSelect } from '@wordpress/data';
import { PluginArea } from '@wordpress/plugins';

/**
 * Internal dependencies
 */
import '../store';
import { SaveButton } from './save-button';
import { Checkbox, Html, Image, Radio, Select, Text, Textarea } from './fields';

// Field types mapped to components. Allows dynamic creation of
// components from section names.
const components = {
	checkbox: Checkbox,
	html: Html,
	image: Image,
	radio: Radio,
	select: Select,
	text: Text,
	textarea: Textarea,
};

/**
 * SettingsComponent
 *
 * @param {{
 *   settings: Object,
 *   sections: Object,
 * }} props
 * @return {SettingsComponent} The main component of the settings app.
 */
function SettingsComponent({ settings, sections }) {
	/**
	 * Reset the form save state to clear “settings saved“ messages.
	 */
	function resetFormSaveState() {
		dispatch('genesis-blocks/global-settings').resetFormSaveState();
	}

	/**
	 * Renders fields for a named section.
	 *
	 * @param {string} section The section name to load fields for.
	 */
	function renderFields(section) {
		if (section.hasOwnProperty('fields') && Array.isArray(section.fields)) {
			const fields = section.fields.map(function (field, index) {
				if (!components.hasOwnProperty(field.type)) {
					return '';
				}
				const Field = components[field.type];
				return <Field key={index} settings={settings} field={field} />;
			});

			if (fields.length > 0) {
				return <>{fields}</>;
			}
		}

		return (
			<p>{__('No fields found for this section.', 'genesis-blocks')}</p>
		);
	}

	/**
	 * Adds the className value that the TabPanel component desires.
	 *
	 * @param {Object} sections The tabs added for sections.
	 */
	function addTabClassNames(sections) {
		// Loop through each tab, and add the className to it.
		for (const section in sections) {
			sections[section].className = 'gb-nav-tab gb-admin-button';
		}

		return sections;
	}

	return (
		<>
			<TabPanel
				className="genesis-blocks-settings-sections"
				activeClass="gb-nav-tab-active"
				onSelect={resetFormSaveState}
				tabs={Object.values(addTabClassNames(sections))}
			>
				{(tab) => (
					<div className="gb-admin-plugin-admin-body">
						<div className="gb-admin-plugin-container">
							{renderFields(tab)}
							<SlotFillProvider>
								<Slot
									name={
										'GenesisBlocksSettings_' +
										tab.name.replace(
											'genesis_blocks_settings_',
											''
										)
									}
								/>
								<PluginArea />
							</SlotFillProvider>
							<SaveButton
								successMessage={__(
									'Settings saved',
									'genesis-blocks'
								)}
								failMessage={__(
									'Saving failed',
									'genesis-blocks'
								)}
								messageDuration="2"
							>
								{__('Save All', 'genesis-blocks')}
							</SaveButton>
						</div>
					</div>
				)}
			</TabPanel>
		</>
	);
}

export const Settings = compose([
	// Subscribe to changes to the settings and sections state.
	withSelect(() => {
		return {
			settings: select('genesis-blocks/global-settings').getSettings(),
			sections: select('genesis-blocks/global-settings').getSections(),
		};
	}),
])(SettingsComponent);
